一、用户中心
- src/container/Profile.js
import React, { Component } from 'react'
import bg from '../../images/login_bg.png'
import profile from '../../images/profile.png'
import './index.less'
import { Link } from 'react-router-dom'
import { connect } from 'react-redux'
import actions from '../../store/actions/session'
class Profile extends Component {
componentDidMount () {
this.props.toValidate()
}
render () {
return ( <div className='profile'>
<div className="profile-bg">
<img src={bg} alt=""/>
<div className="avatar">
<img src={profile} alt=""/>
</div>
{
this.props.user
? <a className='btn'>{this.props.user.username}</a>
: <Link className='btn' to='/login'>登录</Link>
}
</div>
</div>)
}
}
export default connect(state => ({...state.session}), actions)(Profile)
- /Profile/index.css
.profile {
width: 100%;
.profile-bg {
position: relative;
width: 100%;
img {
width: 100%;
}
}
.avatar {
position: absolute;
top: 35%;
width: 60px;
height: 60px;
left: 50%;
margin-left: -30px;
img {
width: 100%;
height: 100%;
}
}
.btn {
position: absolute;
bottom: 20%;
left: 50%;
margin-left: -60px;
background: #fff;
color: #239aea;
width: 120px;
height: 25px;
line-height: 25px;
border-radius: 5px;
text-align: center;
}
}
- src/container/Login.js
import React, { Component } from 'react'
import './index.less'
import Header from "../../component/Header/Header";
import { Link } from 'react-router-dom'
import { connect } from 'react-redux'
import actions from "../../store/actions/session";
import Alert from '../../component/Aleart/Alert'
class Login extends Component {
login = () => {
this.props.toLogin({
username: this.username.value,
password: this.password.value
}, this.props.history.push)
}
render () {
return (<div className='login'>
<Header title='登录' />
<ul className='container'>
<li><input type="text" ref={(el) => this.username = el}/></li>
<li><input type="text" ref={(el) => this.password = el}/></li>
<li><Link to='/reg'>前往注册</Link></li>
<li><button onClick={this.login}>登录</button></li>
<li>
<Alert />
</li>
</ul>
</div>)
}
}
export default connect(state => ({...state.session}), actions)(Login)
- Login/index.less
.login {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #fff;
z-index: 100;
ul {
li {
input {
margin-top: 20px;
width: 100%;
height: 35px;
border-radius: 5px;
box-shadow: none;
outline: none;
border: 1px solid #eee;
-webkit-appearance: none;
}
a {
display: block;
margin-top: 20px;
color: #239aea;
}
button {
margin-top: 20px;
-webkit-appearance: none;
background: #239aea;
color: #fff;
width: 100%;
height: 35px;
text-align: center;
line-height: 35px;
border: none;
outline: none;
border-radius: 5px;
}
}
}
}
- src/container/Reg/Reg.js
import React, { Component } from 'react'
import './index.less'
import Header from "../../component/Header/Header";
import { connect } from 'react-redux'
import actions from "../../store/actions/session";
import Alert from '../../component/Aleart/Alert'
class Reg extends Component {
reg = () => {
this.props.toReg({
username: this.username.value,
password: this.password.value
}, this.props.history.push)
}
render () {
return (<div className='login'>
<Header title='注册' />
<ul className='container'>
<li><input type="text" ref={(el) => {this.username = el}}/></li>
<li><input type="text" ref={(el) => {this.password = el}}/></li>
<li><button onClick={this.reg}>注册</button></li>
<li><Alert /></li>
</ul>
</div>)
}
}
export default connect(state => ({...state.session}), actions)(Reg)
- Reg/index.less
.login {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #fff;
z-index: 100;
ul {
li {
input {
margin-top: 20px;
width: 100%;
height: 35px;
border-radius: 5px;
box-shadow: none;
outline: none;
border: 1px solid #eee;
-webkit-appearance: none;
}
a {
display: block;
margin-top: 20px;
color: #239aea;
}
button {
margin-top: 20px;
-webkit-appearance: none;
background: #239aea;
color: #fff;
width: 100%;
height: 35px;
text-align: center;
line-height: 35px;
border: none;
outline: none;
border-radius: 5px;
}
}
}
}
二、STORE
- store/reducer/session.js
import * as Types from '../action-types'
let initState = {
msg: '',
err: 0,
user: null
}
function reducer(state = initState, action) {
switch (action.type) {
case Types.SET_USER_INFO:
return {...action.payload}
}
return state
}
export default reducer
三、server/package.json
{
"name": "ketang-server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.19.0",
"express": "^4.17.1",
"express-session": "^1.16.2"
}
}
四、server/server.js
let express = require('express')
let bodyParser = require('body-parser')
let session = require('express-session')
let fs = require('fs')
let app = express()
app.use(express.static(__dirname))
app.use(bodyParser.json())
app.use(session({
resave: true, // 保存 cookie
saveUninitialized: true, // 保存未初始化的 session
secret: 'zfpx' // 秘钥
}))
// CORS 跨域资源共享
app.use(function (req, res, next) {
// res.header('Access-Control-Allow-Origin', '*')
res.header('Access-Control-Allow-Origin', 'http://localhost:8080')
res.header('Access-Control-Allow-Credentials', true)
res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Request-With');
res.header('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS')
res.header('X-Powered-By', '3.2.1')
if (req.method.toUpperCase() === 'OPTIONS') {
// 让 options 快速返回
res.send(200)
} else {
next()
}
})
let sliders = require('./database/sliders')
let lessonsDir = __dirname + '/database/lessons.json'
let jdb = (path) => JSON.parse(fs.readFileSync(path, 'utf8'))
app.get('/api/sliders', (req, res) => {
res.send(sliders)
})
app.get('/api/lessons', (req, res) => {
// limit
// offset
// 1
let {limit, offset, type} = req.query
limit = +limit
offset = +offset
let start = offset
let end = offset + limit
let data = jdb(lessonsDir)
let list = data.filter((item, index) => item.type === type)
list = list.slice(start, end)
// 判断是否有更多
let hasMore = true
hasMore = limit * offset < data.length
setTimeout(() => {
res.send({
hasMore,
list
})
}, 2000)
})
let users = [] // 保存所有的用户
let obj = {
msg: '',
code: 0,
user: {}
}
app.post('/api/login', (req, res) => {
let {username, password} = req.body
let isExist = users.find(i => i.username === username)
if (isExist) {
req.session.user = req.body
console.log(users)
res.send({
code: 0,
user: isExist,
msg: 'ok'
})
} else {
res.send({
code: -1,
user: null,
msg: '用户名或者密码错误'
})
}
})
app.post('/api/reg', (req, res) => {
let {username, password} = req.body
console.log(users)
let isExist = users.find(i => i.username === username)
if (isExist) {
res.send({
code: 1,
msg: '该用户名已经被注册',
user: null
})
} else {
users.push({
username,
password
})
res.send({
code: 0,
msg: 'ok',
user: {
username,
password
}
})
}
})
// 使用 session 持久化登录状态
app.get('/api/validate', (req, res) => {
if (req.session.user) {
res.send({
msg: 'ok',
code: 0,
user: req.session.user
})
} else {
res.send({
msg: '用户未登录',
code: -1,
user: null
})
}
})
app.listen(3000, () => console.log('port 3000 is on'))
【发上等愿,结中等缘,享下等福,择高处立,寻平处住,向宽处行】