十.建立数据请求模型以及完成前端登录逻辑
1.后端的Service中及控制器中
return ctx.body = returnInfo(LOGIN.SUCCESS,result)
const uid = usernameExist.get('id');
return {
uid,
username
};
npm i qs -S
3.在utils中新建http.js封装axios
import axios from 'axios';
import qs from 'qs';
export default class HTTP{
axiosPost(options){
axios({
url:options.url,
method:'post',
header:{
'Content-Type':'application/x-www-form-urlencoded'
},
data: qs.stringify(options.data)
}).then((res)=>{
options.success(res.data)
}).catch((err)=>{
options.error(err)
})
}
axiosGet(options){
axios({
url:options.url,
method:'get',
}).then((res)=>{
options.success(res.data)
}).catch((err)=>{
options.error(err)
})
}
}
4.在src中建立config文件夹,且创建config.js
const BASE_URL = "http://localhost:3000/admin/";
const API ={
LOGIN_ACTION: BASE_URL+'login_action'
}
export{
API
}
5.在service中新建login.js
import HTTP from 'utils/http';
import {API} from '../config/config';
export default class LoginService extends HTTP{
loginAction(userInfo){
return new Promise((resolve,reject)=>{
this.axiosPost({
url:API.LOGIN_ACTION,
data:userInfo,
success(data){
resolve(data)
},
error(error){
alert('网络请求失败!');
window.location.reload();
}
})
})
}
}
6.删除Login下Index.js中的测试代码
7.在utils文件夹中建立tools.js
function trimSpace(str){
return str.replace(/\s+/g,'')
}
export{
trimSpace
}
8.loginfrom中引入
import React, { Component } from 'react'
import LoginService from 'services/login'
import {trimSpace} from 'utils/tools'
import './index.scss'
const loginService = new LoginService();
export default class LoginForm extends Component {
constructor(props){
super(props);
this.state={
username:'',
password:''
}
}
onInputTyping(e){
const id = e.target.id,
val = e.target.value;
this.setState({
[id]:val
})
}
async onLoginSubmit(e){
const {username,password} = this.state;
if(trimSpace(username).length<=0){
alert('用户名长度不正确')
return
}
if(trimSpace(password).length<=0){
alert('密码长度不正确')
return
}
const result = await loginService.loginAction({
username:trimSpace(username),
password:trimSpace(password)
})
const errorCode = result.error_code,
errorMsg = result.error_msg;
if(errorCode!==0){
alert(errorMsg+'(errorCode:'+errorCode+')')
return
}
alert('登录成功')
}
render() {
return (
<div className="login-form-wrapper">
<div className="input-box">
<label htmlFor="username" className="iconfont icon-user"></label>
<input
type="text"
id="username"
className="login-input"
placeholder="用户名"
onChange={(e)=>this.onInputTyping(e)}
></input>
</div>
<div className="input-box">
<label htmlFor="password" className="iconfont icon-lock"></label>
<input
type="password"
id='password'
className="login-input"
placeholder="密码"
onChange={(e)=> this.onInputTyping(e)}
></input>
</div>
<div className="input-box">
<button className="btn btn-primary"
onClick={(e)=>this.onLoginSubmit(e)}
>登录后台</button>
</div>
</div>
)
}
}
9.登录成功后跳转
import React, { Component } from 'react'
import Login from "../components/Login"
export default class LoginPage extends Component {
constructor(props){
super(props)
this.state={}
}
render() {
const {history} = this.props
return (
<div className="container">
<Login history={history}/>
</div>
)
}
}
在components中的login/index.js中继续传递
import React, { Component } from 'react'
import Logo from './Logo'
import Form from './Form'
import './index.scss'
export default class Login extends Component {
render() {
const {history} = this.props;
return (
<div className="login-container">
<Logo/>
<Form history={history}/>
</div>
)
}
}
在from中的index.js中继续传递
import React, { Component } from 'react'
import './index.scss'
import Title from './Title'
import LoginForm from './LoginForm'
export default class Form extends Component {
render() {
const {history} = this.props;
return (
<div className="form-wrapper">
<Title/>
<LoginForm history={history}/>
</div>
)
}
}
const {history} = this.props;
alert('登录成功')
history.push('/')
十一.登录验证、跨域设置cookie以及路由跳转
1.后台的控制器中Admin.js存取session
if(!ctx.session.userInfo){
ctx.session.userInfo = result
}
return ctx.body = returnInfo(LOGIN.SUCCESS,ctx.session.userInfo)
2.增加路由,检查登录态
const router = require('koa-router')(),
adminController = require('../controller/admin')
router.prefix('/admin')
router.get('/create_admin',adminController.createAdmin)
router.post('/login_action',adminController.loginAction)
router.get('/login_check',adminController.loginCheck)
module.exports = router;
3.err_config.js中新增状态
NOT_LOGIN_STATUS:{
error_code:10006,
error_msg:'It is not loged status'
},
LOGIN_STATUS:{
error_code:10007,
error_msg:'It is loged status'
}
4.控制器中admin.js
async loginCheck(ctx,next){
if(ctx.session && ctx.session.userInfo){
ctx.body = returnInfo(LOGIN.LOGIN_STATUS)
return
}
ctx.body = returnInfo(LOGIN.NOT_LOGIN_STATUS)
}
5.前端中的config.js
const BASE_URL = "http://localhost:3000/admin/";
const API ={
LOGIN_ACTION: BASE_URL+'login_action',
LOGIN_CHECK:BASE_URL+'login_check'
}
export{
API
}
6.service中的login.js
loginCheck(){
return new Promise((resolve,reject)=>{
this.axiosGet({
url:API.LOGIN_CHECK,
success(data){
resolve(data)
},
error(error){
alert('网路请求失败')
window.location.reload
}
})
})
}
7.在loginform的index.js中
async loginCheck(){
const result = await loginService.loginCheck();
const errorCode = result.error_code;
if(errorCode === 10007){
const {history} = this.props;
history.push('/')
}
}
componentDidMount(){
this.loginCheck();
}
8.携带资质解决cookie跨域存储问题
import axios from 'axios';
import qs from 'qs';
export default class HTTP{
axiosPost(options){
axios({
url:options.url,
method:'post',
withCredentials:true,
header:{
'Content-Type':'application/x-www-form-urlencoded'
},
data: qs.stringify(options.data)
}).then((res)=>{
options.success(res.data)
}).catch((err)=>{
options.error(err)
})
}
axiosGet(options){
axios({
url:options.url,
withCredentials:true,
method:'get',
}).then((res)=>{
options.success(res.data)
}).catch((err)=>{
options.error(err)
})
}
}
后端的app.js
app.use(cors({
origin:function(ctx){
return corsOrigin
},
credentials:true
}))
十二.管理首页登录验证、Header组件、退出登录
1.pages下的index.js首页登录验证
async loginCheck(){
const result = await loginservice.loginCheck();
const errorCode = result.error_code;
if(errorCode === 10006){
const {history} = this.props;
history.push('/login')
}
}
componentDidMount(){
this.loginCheck();
}
import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom'
import { Route, Switch, NavLink, Link } from 'react-router-dom'
import IndexPage from './pages/index'
import LoginPage from './pages/login'
import DetailPage from './pages/sub/detail'
import ListPage from './pages/sub/list'
function App() {
return (
<Router>
<Switch>
<Route component={LoginPage} path="/login"></Route>
<Route path="/" render={ props =>(
<IndexPage history={props.history}>
<Switch>
<Route component={ ListPage } path="/sub/list"></Route>
<Route component={DetailPage} path="/sub/detail"></Route>
</Switch>
</IndexPage>
)}/>
</Switch>
</Router>
);
}
export default App;
2.在components中建立index 再建立Header文件夹,建立index.js index.scss
import React, { Component } from 'react'
import './index.scss'
export default class Header extends Component {
render() {
return (
<header className="header"></header>
)
}
}
.header{
position: fixed;
top: 0;
left: 0;
width: 100%;
min-width: 1200px;
height: 60px;
padding:0 15px;
background-color: #fff;
border-bottom: 1px solid #ddd;
box-sizing: border-box;
}
3.assets中的scss中的common.js中隐去滚动条
html,body,#root,.container{
height: 100%;
}
4.在pages中的index.js文件
import Header from '../components/Index/Header'
<div className="container">
<Header/>
</div>
5.在header中写三个子组件
import React, { Component } from 'react'
import './index.scss'
export default class HeaderLogo extends Component {
render() {
return (
<div className="header-logo-wrapper">
<a href="/" className="logo-link"></a>
</div>
)
}
}
.header-logo-wrapper{
float: left;
height: 100%;
.logo-link{
display: inline-block;
width: 44px;
height: 44px;
margin:8px 10px 0 0;
background:url('../../../../assets/img/logo.png') no-repeat;
background-size: 44px 44px;
}
}
import React, { Component } from 'react'
import './index.scss'
export default class HeaderTitle extends Component {
render() {
return (
<h1 className="header-title">海儿科技官方网站管理后台</h1>
)
}
}
.header-title{
float: left;
line-height: 60px;
font-size: 20px;
}
import React, { Component } from 'react'
import './index.scss'
export default class Logout extends Component {
onLogoutClick(){}
render() {
return (
<span className="header-logout" onClick={()=>this.onLogoutClick()}>安全退出</span>
)
}
}
.header-logout{
float: right;
line-height: 60px;
font-size: 14px;
cursor:pointer
}
import React, { Component } from 'react'
import HeaderLogo from './Logo';
import HeaderTitle from './Title';
import HeaderLogout from './Logout'
import './index.scss'
export default class Header extends Component {
render() {
return (
<header className="header">
<HeaderLogo></HeaderLogo>
<HeaderTitle></HeaderTitle>
<HeaderLogout></HeaderLogout>
</header>
)
}
}
6.在后台中书写路由
const router = require('koa-router')(),
adminController = require('../controller/admin')
router.prefix('/admin')
router.get('/create_admin',adminController.createAdmin)
router.post('/login_action',adminController.loginAction)
router.get('/login_check',adminController.loginCheck)
router.get('/loginout_action',adminController.logoutAction)
module.exports = router;
7.在config的http.js中配置访问路径
const BASE_URL = "http://localhost:3000/admin/";
const API ={
LOGIN_ACTION: BASE_URL+'login_action',
LOGIN_CHECK:BASE_URL+'login_check',
LOGOUT_ACTION:BASE_URL+'logout_action'
}
export{
API
}
8..在service的login.js中
logoutAction(){
return new Promise((resolve,reject)=>{
this.axiosGet({
url:API.LOGOUT_ACTION,
success(data){
resolve(data)
},
error(error){
alert('网络请求失败')
window.location.reload();
}
})
})
}
9.传递history,index.js中
render() {
const {history} = this.props
return (
<div className="container">
<Header history={history}/>
</div>
)
}
import React, { Component } from 'react'
import HeaderLogo from './Logo';
import HeaderTitle from './Title';
import HeaderLogout from './Logout'
import './index.scss'
export default class Header extends Component {
render() {
const {history} = this.props;
return (
<header className="header">
<HeaderLogo></HeaderLogo>
<HeaderTitle></HeaderTitle>
<HeaderLogout history={history}></HeaderLogout>
</header>
)
}
}
10.修改Loginout
import React, { Component } from 'react'
import loginService from '../../../../services/login'
import './index.scss'
const loginService = new LoginService();
export default class Logout extends Component {
async onLogoutClick(){
const cfm = window.confirm('确定退出登录吗?')
if(cfm){
const result= await loginService.logoutAction();
const errorCode = result.error_code;
if(errorCode === 0){
const {history} = this.props;
history.push('/login')
}
}
}
render() {
return (
<span className="header-logout" onClick={()=>this.onLogoutClick()}>安全退出</span>
)
}
}
11.在err_confing.js中
LOGOUT_SUCCESS:{
error_code:0,
error_msg:'Logout is ok'
},
12.在admin的控制器中
async logoutAction(ctx,next){
delete ctx.session.userInfo;
ctx.body = returnInfo(LOGIN.LOGOUT_SUCCESS)
}