Commit 5d02a4f0 by 姜雷

添加登陆和预览

parent fd181f78
import fetch from './fetch'; import fetch from './fetch';
// login // 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 => export const sendMsg = entity =>
fetch({ fetch({
url: '/login/sendMsg', url: '/login/sendMsg',
params: entity,
});
export const login = entity =>
fetch({
url: '/login/app/login.do',
method: 'post', method: 'post',
data: entity, data: entity,
}); });
// base // base
export const fetchRepairArea = () => export const fetchRepairArea = () =>
fetch({ 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 { ...@@ -52,7 +52,12 @@ class ImagePicker extends Component {
done: true, done: true,
})); }));
if (onChange) { if (onChange) {
onChange(filesList); onChange([
{
filesList,
url: fileUrl,
},
]);
} }
}; };
createObjectURL = blob => { createObjectURL = blob => {
......
import React, { Component } from 'react'; import React, { Component } from 'react';
import { createPortal } from 'react-dom'; // import { createPortal } from 'react-dom';
import styles from './style.css'; import styles from './style.css';
import { Carousel } from 'antd-mobile';
import pageIcon from './images/next_pic_btn@2x.png';
class Perview extends Component { class Perview extends Component {
constructor(props) { constructor(props) {
...@@ -21,27 +23,36 @@ class Perview extends Component { ...@@ -21,27 +23,36 @@ class Perview extends Component {
} }
render() { render() {
const { visibility } = this.props; const { data, index } = this.props;
return visibility return (
? createPortal( <div>
<div className={styles}>
<div className={styles.mask} />
<div className={styles.content}> <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.footer}>
<div className={styles.per}> <div className={styles.per}>
<div className={styles.leftIcon} /> <div className={styles.leftIcon}>
<img src={pageIcon} alt="" />
</div>
<div>上一张</div>
</div> </div>
<div className={styles.pagination} /> <div className={styles.pagination}>1/3</div>
<div className={styles.next}> <div className={styles.next}>
<div className={styles.rightIcon} /> <div>下一张</div>
<div className={styles.rightIcon}>
<img src={pageIcon} alt="" />
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
</div>, );
this.node
)
: null;
} }
} }
......
.mask {
composes: mask from '../Popup/style.css';
}
.content { .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'; ...@@ -4,9 +4,8 @@ import { is_weixn } from '../utils';
import { APP_ID } from '../config'; import { APP_ID } from '../config';
import UserInfoContext, { defaultUserinfo } from '../context/userinfo-context'; 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 Home from './Home/Index';
import Report from './report/report';
import Login from './Login/Login'; import Login from './Login/Login';
import PublicCar from './PublicCar/index'; import PublicCar from './PublicCar/index';
import PublicCarDeal from './PublicCarDeal/index'; import PublicCarDeal from './PublicCarDeal/index';
...@@ -14,6 +13,9 @@ import Repair from './Repair/index'; ...@@ -14,6 +13,9 @@ import Repair from './Repair/index';
import RepairDeal from './RepairDeal/index'; import RepairDeal from './RepairDeal/index';
import NoMatch from './NoMatch'; import NoMatch from './NoMatch';
import { wxAuth } from '../api/index';
import { Toast } from 'antd-mobile';
class App extends Component { class App extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
...@@ -61,16 +63,66 @@ class App extends Component { ...@@ -61,16 +63,66 @@ class App extends Component {
} }
return obj; return obj;
}; };
validateUserinfo = props => { renderIndex = props => {
console.log(props); console.log(props);
setTimeout(() => {
const { history, location } = props; const { history, location } = props;
let params = this.getParams(location.search); let params = this.getParams(location.search);
// history.push('/login'); if (params.code) {
console.log('fetch UserInfo');
console.log('redirect', params, history); console.log('redirect', params, history);
}, 1000); wxAuth({
return <Home />; 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 => { updateUserInfo = data => {
this.setState({ this.setState({
...@@ -87,8 +139,8 @@ class App extends Component { ...@@ -87,8 +139,8 @@ class App extends Component {
<div className="App"> <div className="App">
<UserInfoContext.Provider value={userContext}> <UserInfoContext.Provider value={userContext}>
<Switch> <Switch>
<Route exact path="/" render={this.validateUserinfo} /> <Route exact path="/" render={this.renderIndex} />
<Route path="/report" component={Report} /> <Route path="/home" component={Home} />
<Route path="/login" component={Login} /> <Route path="/login" component={Login} />
<Route path="/publicCar" component={PublicCar} /> <Route path="/publicCar" component={PublicCar} />
<Route path="/publicCarDeal" component={PublicCarDeal} /> <Route path="/publicCarDeal" component={PublicCarDeal} />
......
...@@ -8,7 +8,15 @@ export class Index extends React.Component { ...@@ -8,7 +8,15 @@ export class Index extends React.Component {
}; };
render() { 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 React, { Component } from 'react';
import { Redirect } from 'react-router-dom'; import { Redirect } from 'react-router-dom';
import styles from './style.css'; import styles from './style.css';
import logoIcon from './images/school_logo@2x.png';
const fakeAuth = { import logoWord from './images/school_word_logo@2x.png';
isAuthenticated: false, import { Button, Modal, Toast } from 'antd-mobile';
authenticate(cb) { import { getVcode, sendMsg, login } from '../../api/index';
this.isAuthenticated = true; import CodeView from '../../components/CodeView/CodeView';
setTimeout(cb, 100); // fake async import UserInfoContext from '../../context/userinfo-context';
},
signout(cb) {
this.isAuthenticated = false;
setTimeout(cb, 100);
},
};
class Login extends Component { class Login extends Component {
state = { constructor(props) {
super(props);
this.state = {
redirectToReferrer: false, 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 = () => { getVcodeHandle = () => {
fakeAuth.authenticate(() => { 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 }); this.setState({ redirectToReferrer: true });
console.log(res);
})
.catch(err => {
console.log(err);
}); });
// fakeAuth.authenticate(() => {
// this.setState({ redirectToReferrer: true });
// });
}; };
render() { render() {
const { from } = this.props.location.state || { from: { pathname: '/' } }; // const { from } = this.props.location.state || { from: { pathname: '/' } };
const { redirectToReferrer } = this.state; const {
redirectToReferrer,
sending,
count,
cellphone,
vcodeDialogVisible,
vcode,
svcode,
code,
} = this.state;
if (redirectToReferrer) { if (redirectToReferrer) {
return <Redirect to={from} />; return <Redirect to={{ pathname: '/home' }} />;
} }
return ( return (
<div className={styles.Login}> <div className={styles.Login}>
<h2>Login</h2> <div className={styles.loginBox}>
<button onClick={this.login}>Log in</button> <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> </div>
); );
} }
} }
export default Login; export default props => (
<UserInfoContext.Consumer>
{({ userinfo, updateUserInfo }) => (
<Login {...props} updateUserInfo={updateUserInfo} />
)}
</UserInfoContext.Consumer>
);
.Login { .Login {
height: 300px;
text-align: center; 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 React, { Component } from 'react';
import styles from './style.css'; 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 peopleIcon from './images/repair_people_icon@2x.png';
import phoneIcon from './images/phone_tel_icon@2x.png'; import phoneIcon from './images/phone_tel_icon@2x.png';
import roleIcon from './images/user_role_icon@2x.png'; import roleIcon from './images/user_role_icon@2x.png';
...@@ -32,7 +32,7 @@ class ReprtRepair extends Component { ...@@ -32,7 +32,7 @@ class ReprtRepair extends Component {
address: '', address: '',
uploadImg: [null, null, null], uploadImg: [null, null, null],
}, },
perviewVisibility: true, perviewVisibility: false,
perviewIndex: 0, perviewIndex: 0,
}; };
} }
...@@ -114,7 +114,6 @@ class ReprtRepair extends Component { ...@@ -114,7 +114,6 @@ class ReprtRepair extends Component {
})); }));
}; };
showViewHandle = index => { showViewHandle = index => {
console.log('showViewHandle');
console.log(index); console.log(index);
this.setState({ this.setState({
perviewVisibility: true, perviewVisibility: true,
...@@ -189,6 +188,11 @@ class ReprtRepair extends Component { ...@@ -189,6 +188,11 @@ class ReprtRepair extends Component {
console.log(err); console.log(err);
}); });
}; };
resetDialog = () => {
this.setState({
perviewVisibility: false,
});
};
render() { render() {
const { const {
applyForm, applyForm,
...@@ -338,11 +342,16 @@ class ReprtRepair extends Component { ...@@ -338,11 +342,16 @@ class ReprtRepair extends Component {
<Button className={styles.applyBtn} onClick={this.startApply}> <Button className={styles.applyBtn} onClick={this.startApply}>
提交 提交
</Button> </Button>
<Perview <Modal
visibility={perviewVisibility} className={styles.perViewDialog}
data={applyForm.uploadImg} visible={perviewVisibility}
index={perviewIndex} transparent
/> maskClosable={true}
onClose={this.resetDialog}
title=""
>
<Perview data={applyForm.uploadImg} index={perviewIndex} />
</Modal>
</div> </div>
); );
} }
......
...@@ -196,3 +196,7 @@ ...@@ -196,3 +196,7 @@
text-align: center; text-align: center;
padding: 50px 0; 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'; import React from 'react';
export const defaultUserinfo = { export const defaultUserinfo = {
openid: '15', login: false,
userId: '15',
cellphone: '',
name: '', name: '',
phone: '', department: '',
author: [],
}; };
export const UserContext = React.createContext({ 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