Compare commits
merge into: MYW:master
MYW:dev
MYW:master
pull from: MYW:dev
MYW:dev
MYW:master
4 Commits
Author | SHA1 | Message | Date |
---|---|---|---|
MYW | 5c67f4efbb |
project
|
2 years ago |
MYW | aed87f4e7d |
project
|
2 years ago |
MYW | 2583502638 |
project
|
2 years ago |
MYW | 511fe85959 |
project
|
2 years ago |
21 changed files with 12061 additions and 0 deletions
-
6.babelrc
-
1.gitignore
-
11index.html
-
11556package-lock.json
-
41package.json
-
12src/App.js
-
16src/components/button/Button.js
-
5src/components/index.js
-
49src/components/input/EmailInput.js
-
51src/components/input/PasswdInput.js
-
10src/index.js
-
11src/pages/layouts/Layouts.js
-
41src/pages/login/Login.js
-
24src/router/index.js
-
12src/router/routes.js
-
22src/store/LoginStore.js
-
51src/styles/index.css
-
59src/styles/index.less
-
25src/utils/http.js
-
18src/utils/token.js
-
40webpack.config.js
@ -0,0 +1,6 @@ |
|||
{ |
|||
"presets": [ |
|||
"@babel/preset-env", |
|||
"@babel/preset-react" |
|||
] |
|||
} |
@ -0,0 +1 @@ |
|||
node_modules |
@ -0,0 +1,11 @@ |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<title>Document</title> |
|||
</head> |
|||
<body> |
|||
<div id="root"></div> |
|||
</body> |
|||
</html> |
11556
package-lock.json
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,41 @@ |
|||
{ |
|||
"name": "react-project", |
|||
"version": "1.0.0", |
|||
"description": "", |
|||
"main": "index.js", |
|||
"scripts": { |
|||
"start": "webpack server --open --mode development", |
|||
"build": "webpack --mode production" |
|||
}, |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "https://git.deepdev.pro/MYW/react-project.git" |
|||
}, |
|||
"keywords": [], |
|||
"author": "", |
|||
"license": "ISC", |
|||
"dependencies": { |
|||
"axios": "^0.27.2", |
|||
"mobx": "^6.6.1", |
|||
"mobx-react-lite": "^3.4.0", |
|||
"react": "^18.2.0", |
|||
"react-dom": "^18.2.0", |
|||
"react-router-dom": "^6.3.0", |
|||
"uuid": "^8.3.2" |
|||
}, |
|||
"devDependencies": { |
|||
"@babel/core": "^7.18.10", |
|||
"@babel/preset-env": "^7.18.10", |
|||
"@babel/preset-react": "^7.18.6", |
|||
"babel-loader": "^8.2.5", |
|||
"css-loader": "^6.7.1", |
|||
"html-loader": "^4.1.0", |
|||
"html-webpack-plugin": "^5.5.0", |
|||
"less": "^4.1.3", |
|||
"style-loader": "^3.3.1", |
|||
"typescript": "^4.7.4", |
|||
"webpack": "^5.74.0", |
|||
"webpack-cli": "^4.10.0", |
|||
"webpack-dev-server": "^4.10.0" |
|||
} |
|||
} |
@ -0,0 +1,12 @@ |
|||
import React from 'react'; |
|||
import Router from './router/index'; |
|||
|
|||
function App() { |
|||
return ( |
|||
<div className="App"> |
|||
<Router /> |
|||
</div> |
|||
); |
|||
} |
|||
|
|||
export default App; |
@ -0,0 +1,16 @@ |
|||
import React from "react"; |
|||
|
|||
function LoginButton (props) { |
|||
|
|||
const { onSubmit } = props |
|||
|
|||
return( |
|||
<button |
|||
className="submit" |
|||
type="submit" |
|||
onClick={() => onSubmit()} |
|||
>提交</button> |
|||
) |
|||
} |
|||
|
|||
export default LoginButton |
@ -0,0 +1,5 @@ |
|||
import EmailInput from "./input/EmailInput"; |
|||
import PasswdInput from "./input/PasswdInput"; |
|||
import LoginButton from "./button/Button"; |
|||
|
|||
export { EmailInput, LoginButton, PasswdInput} |
@ -0,0 +1,49 @@ |
|||
import React, { useState } from 'react'; |
|||
|
|||
const EmailInput = (props) => { |
|||
const { onChange } = props; |
|||
|
|||
const [value, setValue] = useState(''); |
|||
const [EmailMessage, setEmailMessage] = useState(''); |
|||
|
|||
const EmailInputChange = e => { |
|||
setValue(e.target.value); |
|||
|
|||
if (judge() && onChange) { |
|||
onChange(e.target.value); |
|||
} |
|||
}; |
|||
|
|||
const judge = () => { |
|||
const rules = /^[-_A-Za-z0-9]+@([_A-Za-z0-9]+\.)+[A-Za-z0-9]{2,3}$/; |
|||
if (rules.test(value)) { |
|||
setEmailMessage(''); |
|||
return true; |
|||
} else { |
|||
setEmailMessage('请输入正确邮箱'); |
|||
} |
|||
return false; |
|||
}; |
|||
|
|||
const EmailInputOnBlur = () => { |
|||
judge(); |
|||
}; |
|||
|
|||
return ( |
|||
<div> |
|||
<input |
|||
className='email' |
|||
type="text" |
|||
placeholder="请输入邮箱" |
|||
value={value} |
|||
onChange={e => EmailInputChange(e)} |
|||
onBlur={EmailInputOnBlur} |
|||
/> |
|||
<p |
|||
>{EmailMessage}</p> |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
export default EmailInput; |
|||
|
@ -0,0 +1,51 @@ |
|||
import React, { useState } from "react"; |
|||
|
|||
const PasswdInput = (props) => { |
|||
|
|||
const {onChange} = props |
|||
|
|||
const [value, setValue] = useState('') |
|||
const [passwdMessage, setpasswdMessage] = useState('') |
|||
|
|||
const PasswdInputChange = (e) => { |
|||
setValue(e.target.value) |
|||
|
|||
if( Judge() && onChange ){ |
|||
onChange(e.target.value); |
|||
} |
|||
} |
|||
|
|||
const Judge = () => { |
|||
const rules = /^[\w_-]{6,16}$/ |
|||
if(rules.test(value)) { |
|||
setpasswdMessage('') |
|||
return true |
|||
} else { |
|||
setpasswdMessage('请输入6~16位的密码') |
|||
return false |
|||
} |
|||
} |
|||
|
|||
const PasswdInputOnBlur = () => { |
|||
Judge() |
|||
}; |
|||
|
|||
return ( |
|||
<div> |
|||
<input |
|||
className="passwd" |
|||
type="text" |
|||
placeholder="请输入密码" |
|||
value={value} |
|||
onChange={e => PasswdInputChange(e)} |
|||
onBlur={PasswdInputOnBlur} |
|||
/> |
|||
<p |
|||
>{passwdMessage}</p> |
|||
</div> |
|||
) |
|||
} |
|||
|
|||
|
|||
|
|||
export default PasswdInput |
@ -0,0 +1,10 @@ |
|||
import React from 'react'; |
|||
import ReactDOM from 'react-dom/client'; |
|||
import App from './App' |
|||
import './styles/index.css' |
|||
|
|||
const root = ReactDOM.createRoot(document.getElementById('root')) |
|||
|
|||
root.render( |
|||
<App /> |
|||
) |
@ -0,0 +1,11 @@ |
|||
import React from "react"; |
|||
|
|||
function Layouts ({children}) { |
|||
return ( |
|||
<> |
|||
<div className="page_container">{children}</div> |
|||
</> |
|||
) |
|||
} |
|||
|
|||
export default Layouts |
@ -0,0 +1,41 @@ |
|||
import React, { useState } from "react" |
|||
import { EmailInput, LoginButton, PasswdInput } from '../../components/index' |
|||
import loginStore from '../../store/LoginStore' |
|||
import { observer } from 'mobx-react-lite' |
|||
import Layouts from "../layouts/Layouts" |
|||
|
|||
|
|||
function Login() { |
|||
|
|||
const [email, setEmail] = useState('') |
|||
const [passwd, setPasswd] = useState('') |
|||
|
|||
|
|||
const onSubmit = async (emailValue, passwdValue) => { |
|||
if (email === '' || passwd === '') { |
|||
alert('请输入密码或账号') |
|||
} else { |
|||
await loginStore.getToken({ email: emailValue, password: passwdValue, recaptcha: 'shoa-P8fe1pho<u4' }) |
|||
} |
|||
|
|||
} |
|||
|
|||
return ( |
|||
<Layouts> |
|||
<div className="login_container"> |
|||
<h1 className="header">登入</h1> |
|||
<p className="text">邮箱</p> |
|||
<EmailInput |
|||
onChange={(value) => { setEmail(value) }} |
|||
></EmailInput> |
|||
<p className="text">密码</p> |
|||
<PasswdInput |
|||
onChange={(value) => { setPasswd(value) }} |
|||
></PasswdInput> |
|||
<LoginButton onSubmit={() => onSubmit(email, passwd)}></LoginButton> |
|||
</div> |
|||
</Layouts> |
|||
) |
|||
} |
|||
|
|||
export default observer(Login) |
@ -0,0 +1,24 @@ |
|||
import React from 'react'; |
|||
import routes from "./routes"; |
|||
import { BrowserRouter, Route, Routes } from "react-router-dom"; |
|||
|
|||
function router() { |
|||
return ( |
|||
<BrowserRouter> |
|||
<Routes> |
|||
{routes.map((item) => { |
|||
return ( |
|||
<Route |
|||
key={item.id} |
|||
path={item.path} |
|||
element={<item.component/>} |
|||
/> |
|||
); |
|||
})} |
|||
</Routes> |
|||
</BrowserRouter> |
|||
); |
|||
} |
|||
|
|||
|
|||
export default router; |
@ -0,0 +1,12 @@ |
|||
import { lazy } from "react" |
|||
import { v4 as uuid} from 'uuid' |
|||
|
|||
const routers = [ |
|||
{ |
|||
id: uuid(), |
|||
path: '/login', |
|||
component: lazy(() => import('../pages/login/Login')) |
|||
} |
|||
] |
|||
|
|||
export default routers |
@ -0,0 +1,22 @@ |
|||
import http from '../utils/http' |
|||
import { makeAutoObservable } from 'mobx' |
|||
import { setToken, getToken } from '../utils/token' |
|||
|
|||
class LoginStore { |
|||
|
|||
token = getToken() || '' |
|||
|
|||
constructor() { |
|||
makeAutoObservable(this) |
|||
} |
|||
|
|||
getToken = async ({ email, password, recaptcha }) => { |
|||
const res = await http.post('/user/login', { email, password, recaptcha }) |
|||
console.log(res.data) |
|||
this.token = res.data.accessToken |
|||
setToken(this.token) |
|||
} |
|||
} |
|||
|
|||
const loginStore = new LoginStore() |
|||
export default loginStore |
@ -0,0 +1,51 @@ |
|||
* { |
|||
margin: 0; |
|||
padding: 0; |
|||
} |
|||
body { |
|||
background-color: #F5F5F5; |
|||
} |
|||
.page_container { |
|||
position: relative; |
|||
width: 80%; |
|||
height: 100%; |
|||
margin: 0 auto; |
|||
background-color: #FFFFFF; |
|||
} |
|||
.login_container { |
|||
display: flex; |
|||
width: 500px; |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
align-items: center; |
|||
position: absolute; |
|||
left: 50%; |
|||
top: 20%; |
|||
transform: translate(-50%, -50%); |
|||
} |
|||
.header { |
|||
font-weight: 400; |
|||
margin-bottom: 30px; |
|||
} |
|||
.text { |
|||
margin-left: -265px; |
|||
} |
|||
.email, |
|||
.passwd, |
|||
.submit { |
|||
width: 300px; |
|||
height: 30px; |
|||
border: none; |
|||
border-radius: 5px; |
|||
} |
|||
.email, |
|||
.passwd { |
|||
background-color: #F5F5F5; |
|||
margin-bottom: 20px; |
|||
} |
|||
.submit { |
|||
width: 300px; |
|||
margin-top: 10px; |
|||
color: #FFFFFF; |
|||
background-color: #00BFFF; |
|||
} |
@ -0,0 +1,59 @@ |
|||
* { |
|||
margin: 0; |
|||
padding: 0; |
|||
} |
|||
|
|||
body { |
|||
background-color: #F5F5F5; |
|||
} |
|||
|
|||
.page_container { |
|||
position: relative; |
|||
width: 80%; |
|||
height: 100%; |
|||
margin: 0 auto; |
|||
background-color: #FFFFFF; |
|||
} |
|||
|
|||
.login_container { |
|||
display: flex; |
|||
width: 500px; |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
align-items: center; |
|||
position: absolute; |
|||
left: 50%; |
|||
top: 20%; |
|||
transform: translate(-50%, -50%); |
|||
} |
|||
|
|||
.header { |
|||
font-weight: 400; |
|||
margin-bottom: 30px; |
|||
} |
|||
|
|||
.text { |
|||
margin-left: -265px; |
|||
} |
|||
|
|||
.email, |
|||
.passwd, |
|||
.submit { |
|||
width: 300px; |
|||
height: 30px; |
|||
border: none; |
|||
border-radius: 5px; |
|||
} |
|||
|
|||
.email, |
|||
.passwd { |
|||
background-color: #F5F5F5; |
|||
margin-bottom: 20px; |
|||
} |
|||
|
|||
.submit { |
|||
width: 300px; |
|||
margin-top: 10px; |
|||
color: #FFFFFF; |
|||
background-color: #00BFFF; |
|||
} |
@ -0,0 +1,25 @@ |
|||
import axios from "axios"; |
|||
|
|||
const http = axios.create({ |
|||
baseURL: 'http://mobie.api.test.com', |
|||
timeout: 5000, |
|||
}) |
|||
|
|||
// 添加请求拦截器
|
|||
http.interceptors.request.use(function (config) { |
|||
return config; |
|||
}, function (error) { |
|||
return Promise.reject(error); |
|||
}); |
|||
|
|||
// 添加响应拦截器
|
|||
http.interceptors.response.use(function (response) { |
|||
return response.data; |
|||
}, function (error) { |
|||
if(error.response.status === 422) { |
|||
alert('邮箱或者密码错误') |
|||
} |
|||
return Promise.reject(error); |
|||
}); |
|||
|
|||
export default http |
@ -0,0 +1,18 @@ |
|||
// 封装 localStorage 存取 token
|
|||
|
|||
const key = 'pc-key' |
|||
|
|||
// 存取 token
|
|||
const setToken = (token) => { |
|||
return window.localStorage.setItem(key, token) |
|||
} |
|||
|
|||
// 获取 token
|
|||
const getToken = () => { |
|||
return window.localStorage.getItem(key) |
|||
} |
|||
|
|||
export { |
|||
setToken, |
|||
getToken |
|||
} |
@ -0,0 +1,40 @@ |
|||
const HtmlWebPackPlugin = require("html-webpack-plugin"); |
|||
|
|||
module.exports = { |
|||
module: { |
|||
rules: [ |
|||
{ |
|||
test: /\.(js|jsx)$/, |
|||
exclude: /node_modules/, |
|||
use: { |
|||
loader: "babel-loader" |
|||
} |
|||
}, |
|||
{ |
|||
test: /\.html$/, |
|||
use: [ |
|||
{ |
|||
loader: "html-loader" |
|||
}, |
|||
] |
|||
}, |
|||
{ |
|||
test: /\.css$/, |
|||
use: ['style-loader', 'css-loader'], |
|||
}, |
|||
{ |
|||
test: /\.less$/, |
|||
use: ['style-loader', 'css-loader', 'postcss-loader', 'less-loader'], |
|||
} |
|||
] |
|||
}, |
|||
plugins: [ |
|||
new HtmlWebPackPlugin({ |
|||
template: "./index.html", |
|||
filename: "./index.html" |
|||
}) |
|||
], |
|||
devServer: { |
|||
historyApiFallback: true |
|||
} |
|||
}; |
Write
Preview
Loading…
Cancel
Save
Reference in new issue