一、用户中心

  • src/container/Profile.js
  1. import React, { Component } from 'react'
  2. import bg from '../../images/login_bg.png'
  3. import profile from '../../images/profile.png'
  4. import './index.less'
  5. import { Link } from 'react-router-dom'
  6. import { connect } from 'react-redux'
  7. import actions from '../../store/actions/session'
  8. class Profile extends Component {
  9. componentDidMount () {
  10. this.props.toValidate()
  11. }
  12. render () {
  13. return ( <div className='profile'>
  14. <div className="profile-bg">
  15. <img src={bg} alt=""/>
  16. <div className="avatar">
  17. <img src={profile} alt=""/>
  18. </div>
  19. {
  20. this.props.user
  21. ? <a className='btn'>{this.props.user.username}</a>
  22. : <Link className='btn' to='/login'>登录</Link>
  23. }
  24. </div>
  25. </div>)
  26. }
  27. }
  28. export default connect(state => ({...state.session}), actions)(Profile)
  • /Profile/index.css
  1. .profile {
  2. width: 100%;
  3. .profile-bg {
  4. position: relative;
  5. width: 100%;
  6. img {
  7. width: 100%;
  8. }
  9. }
  10. .avatar {
  11. position: absolute;
  12. top: 35%;
  13. width: 60px;
  14. height: 60px;
  15. left: 50%;
  16. margin-left: -30px;
  17. img {
  18. width: 100%;
  19. height: 100%;
  20. }
  21. }
  22. .btn {
  23. position: absolute;
  24. bottom: 20%;
  25. left: 50%;
  26. margin-left: -60px;
  27. background: #fff;
  28. color: #239aea;
  29. width: 120px;
  30. height: 25px;
  31. line-height: 25px;
  32. border-radius: 5px;
  33. text-align: center;
  34. }
  35. }
  • src/container/Login.js
  1. import React, { Component } from 'react'
  2. import './index.less'
  3. import Header from "../../component/Header/Header";
  4. import { Link } from 'react-router-dom'
  5. import { connect } from 'react-redux'
  6. import actions from "../../store/actions/session";
  7. import Alert from '../../component/Aleart/Alert'
  8. class Login extends Component {
  9. login = () => {
  10. this.props.toLogin({
  11. username: this.username.value,
  12. password: this.password.value
  13. }, this.props.history.push)
  14. }
  15. render () {
  16. return (<div className='login'>
  17. <Header title='登录' />
  18. <ul className='container'>
  19. <li><input type="text" ref={(el) => this.username = el}/></li>
  20. <li><input type="text" ref={(el) => this.password = el}/></li>
  21. <li><Link to='/reg'>前往注册</Link></li>
  22. <li><button onClick={this.login}>登录</button></li>
  23. <li>
  24. <Alert />
  25. </li>
  26. </ul>
  27. </div>)
  28. }
  29. }
  30. export default connect(state => ({...state.session}), actions)(Login)
  • Login/index.less
  1. .login {
  2. position: absolute;
  3. top: 0;
  4. left: 0;
  5. right: 0;
  6. bottom: 0;
  7. background: #fff;
  8. z-index: 100;
  9. ul {
  10. li {
  11. input {
  12. margin-top: 20px;
  13. width: 100%;
  14. height: 35px;
  15. border-radius: 5px;
  16. box-shadow: none;
  17. outline: none;
  18. border: 1px solid #eee;
  19. -webkit-appearance: none;
  20. }
  21. a {
  22. display: block;
  23. margin-top: 20px;
  24. color: #239aea;
  25. }
  26. button {
  27. margin-top: 20px;
  28. -webkit-appearance: none;
  29. background: #239aea;
  30. color: #fff;
  31. width: 100%;
  32. height: 35px;
  33. text-align: center;
  34. line-height: 35px;
  35. border: none;
  36. outline: none;
  37. border-radius: 5px;
  38. }
  39. }
  40. }
  41. }
  • src/container/Reg/Reg.js
  1. import React, { Component } from 'react'
  2. import './index.less'
  3. import Header from "../../component/Header/Header";
  4. import { connect } from 'react-redux'
  5. import actions from "../../store/actions/session";
  6. import Alert from '../../component/Aleart/Alert'
  7. class Reg extends Component {
  8. reg = () => {
  9. this.props.toReg({
  10. username: this.username.value,
  11. password: this.password.value
  12. }, this.props.history.push)
  13. }
  14. render () {
  15. return (<div className='login'>
  16. <Header title='注册' />
  17. <ul className='container'>
  18. <li><input type="text" ref={(el) => {this.username = el}}/></li>
  19. <li><input type="text" ref={(el) => {this.password = el}}/></li>
  20. <li><button onClick={this.reg}>注册</button></li>
  21. <li><Alert /></li>
  22. </ul>
  23. </div>)
  24. }
  25. }
  26. export default connect(state => ({...state.session}), actions)(Reg)
  • Reg/index.less
  1. .login {
  2. position: absolute;
  3. top: 0;
  4. left: 0;
  5. right: 0;
  6. bottom: 0;
  7. background: #fff;
  8. z-index: 100;
  9. ul {
  10. li {
  11. input {
  12. margin-top: 20px;
  13. width: 100%;
  14. height: 35px;
  15. border-radius: 5px;
  16. box-shadow: none;
  17. outline: none;
  18. border: 1px solid #eee;
  19. -webkit-appearance: none;
  20. }
  21. a {
  22. display: block;
  23. margin-top: 20px;
  24. color: #239aea;
  25. }
  26. button {
  27. margin-top: 20px;
  28. -webkit-appearance: none;
  29. background: #239aea;
  30. color: #fff;
  31. width: 100%;
  32. height: 35px;
  33. text-align: center;
  34. line-height: 35px;
  35. border: none;
  36. outline: none;
  37. border-radius: 5px;
  38. }
  39. }
  40. }
  41. }

二、STORE

  • store/reducer/session.js
  1. import * as Types from '../action-types'
  2. let initState = {
  3. msg: '',
  4. err: 0,
  5. user: null
  6. }
  7. function reducer(state = initState, action) {
  8. switch (action.type) {
  9. case Types.SET_USER_INFO:
  10. return {...action.payload}
  11. }
  12. return state
  13. }
  14. export default reducer

三、server/package.json

  1. {
  2. "name": "ketang-server",
  3. "version": "1.0.0",
  4. "description": "",
  5. "main": "index.js",
  6. "scripts": {
  7. "test": "echo \"Error: no test specified\" && exit 1"
  8. },
  9. "keywords": [],
  10. "author": "",
  11. "license": "ISC",
  12. "dependencies": {
  13. "body-parser": "^1.19.0",
  14. "express": "^4.17.1",
  15. "express-session": "^1.16.2"
  16. }
  17. }

四、server/server.js

  1. let express = require('express')
  2. let bodyParser = require('body-parser')
  3. let session = require('express-session')
  4. let fs = require('fs')
  5. let app = express()
  6. app.use(express.static(__dirname))
  7. app.use(bodyParser.json())
  8. app.use(session({
  9. resave: true, // 保存 cookie
  10. saveUninitialized: true, // 保存未初始化的 session
  11. secret: 'zfpx' // 秘钥
  12. }))
  13. // CORS 跨域资源共享
  14. app.use(function (req, res, next) {
  15. // res.header('Access-Control-Allow-Origin', '*')
  16. res.header('Access-Control-Allow-Origin', 'http://localhost:8080')
  17. res.header('Access-Control-Allow-Credentials', true)
  18. res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Request-With');
  19. res.header('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS')
  20. res.header('X-Powered-By', '3.2.1')
  21. if (req.method.toUpperCase() === 'OPTIONS') {
  22. // 让 options 快速返回
  23. res.send(200)
  24. } else {
  25. next()
  26. }
  27. })
  28. let sliders = require('./database/sliders')
  29. let lessonsDir = __dirname + '/database/lessons.json'
  30. let jdb = (path) => JSON.parse(fs.readFileSync(path, 'utf8'))
  31. app.get('/api/sliders', (req, res) => {
  32. res.send(sliders)
  33. })
  34. app.get('/api/lessons', (req, res) => {
  35. // limit
  36. // offset
  37. // 1
  38. let {limit, offset, type} = req.query
  39. limit = +limit
  40. offset = +offset
  41. let start = offset
  42. let end = offset + limit
  43. let data = jdb(lessonsDir)
  44. let list = data.filter((item, index) => item.type === type)
  45. list = list.slice(start, end)
  46. // 判断是否有更多
  47. let hasMore = true
  48. hasMore = limit * offset < data.length
  49. setTimeout(() => {
  50. res.send({
  51. hasMore,
  52. list
  53. })
  54. }, 2000)
  55. })
  56. let users = [] // 保存所有的用户
  57. let obj = {
  58. msg: '',
  59. code: 0,
  60. user: {}
  61. }
  62. app.post('/api/login', (req, res) => {
  63. let {username, password} = req.body
  64. let isExist = users.find(i => i.username === username)
  65. if (isExist) {
  66. req.session.user = req.body
  67. console.log(users)
  68. res.send({
  69. code: 0,
  70. user: isExist,
  71. msg: 'ok'
  72. })
  73. } else {
  74. res.send({
  75. code: -1,
  76. user: null,
  77. msg: '用户名或者密码错误'
  78. })
  79. }
  80. })
  81. app.post('/api/reg', (req, res) => {
  82. let {username, password} = req.body
  83. console.log(users)
  84. let isExist = users.find(i => i.username === username)
  85. if (isExist) {
  86. res.send({
  87. code: 1,
  88. msg: '该用户名已经被注册',
  89. user: null
  90. })
  91. } else {
  92. users.push({
  93. username,
  94. password
  95. })
  96. res.send({
  97. code: 0,
  98. msg: 'ok',
  99. user: {
  100. username,
  101. password
  102. }
  103. })
  104. }
  105. })
  106. // 使用 session 持久化登录状态
  107. app.get('/api/validate', (req, res) => {
  108. if (req.session.user) {
  109. res.send({
  110. msg: 'ok',
  111. code: 0,
  112. user: req.session.user
  113. })
  114. } else {
  115. res.send({
  116. msg: '用户未登录',
  117. code: -1,
  118. user: null
  119. })
  120. }
  121. })
  122. app.listen(3000, () => console.log('port 3000 is on'))