feat: save login token to localStorage for test

This commit is contained in:
LittleBoy 2023-02-27 21:45:44 +08:00
parent b951e34206
commit 6f6e6997ad
7 changed files with 65 additions and 24 deletions

View File

@ -5,6 +5,7 @@ const AppConfig = {
API_PREFIX: 'http://chat.wx.wm-app.xyz', API_PREFIX: 'http://chat.wx.wm-app.xyz',
DEPLOY_DIR: '/', DEPLOY_DIR: '/',
PUBLIC_PATH: '/', PUBLIC_PATH: '/',
LOGIN_TOKEN_KEY: 'chat.user.token',
}, },
test: { test: {
CLIENT_ID: 'uziRFTVYkcgnGjAx', CLIENT_ID: 'uziRFTVYkcgnGjAx',
@ -12,6 +13,7 @@ const AppConfig = {
API_PREFIX: 'http://chat.wx.wm-app.xyz', API_PREFIX: 'http://chat.wx.wm-app.xyz',
DEPLOY_DIR: (process.env.DEPLOY_DIR || '/'), DEPLOY_DIR: (process.env.DEPLOY_DIR || '/'),
PUBLIC_PATH: (process.env.PUBLIC_PATH || './'), PUBLIC_PATH: (process.env.PUBLIC_PATH || './'),
LOGIN_TOKEN_KEY: 'chat.user.token',
}, },
production: { production: {
CLIENT_ID: 'aVjsh87iWEuhZdWC', CLIENT_ID: 'aVjsh87iWEuhZdWC',
@ -19,6 +21,7 @@ const AppConfig = {
API_PREFIX: 'http://chat.wx.wm-app.xyz', API_PREFIX: 'http://chat.wx.wm-app.xyz',
DEPLOY_DIR: (process.env.DEPLOY_DIR || '/'), DEPLOY_DIR: (process.env.DEPLOY_DIR || '/'),
PUBLIC_PATH: (process.env.PUBLIC_PATH || './'), PUBLIC_PATH: (process.env.PUBLIC_PATH || './'),
LOGIN_TOKEN_KEY: 'chat.user.token',
} }
} }
export default AppConfig export default AppConfig

View File

@ -1,10 +1,11 @@
import React, {useEffect, useState} from 'react' import React, {useEffect, useState} from 'react'
import Login from "./components/Login"; import Login from "./components/Login";
import {useSetState} from "ahooks"; import {useMount, useSetState} from "ahooks";
import {info, UserModel} from "./services/api"; import {info, UserModel} from "./services/api";
import Vip from "./components/vip"; import Vip from "./components/vip";
import Button from "./components/Button"; import Button from "./components/Button";
import {io} from 'socket.io-client' import {io} from 'socket.io-client'
import { useEffectOnce } from './utils/useEffectOnce';
type MessageItem = { type MessageItem = {
@ -14,7 +15,7 @@ type MessageItem = {
content: string[]; content: string[];
avatar: string; avatar: string;
} }
const LOGIN_TOKEN_KEY = APP_CONFIG.LOGIN_TOKEN_KEY;
const avatar = 'https://www.cdnjson.com/images/2023/01/31/qwrgFf.jpg', const avatar = 'https://www.cdnjson.com/images/2023/01/31/qwrgFf.jpg',
avatar1 = 'https://www.cdnjson.com/images/2023/02/25/AI.png', avatar1 = 'https://www.cdnjson.com/images/2023/02/25/AI.png',
globalMessageList: MessageItem[] = [ globalMessageList: MessageItem[] = [
@ -29,8 +30,10 @@ const avatar = 'https://www.cdnjson.com/images/2023/01/31/qwrgFf.jpg',
avatar: avatar1 avatar: avatar1
}, },
], ],
socket = io(APP_CONFIG.API_PREFIX, { socket = io(APP_CONFIG.API_PREFIX, {
autoConnect: false autoConnect: false,
path:`/socket.io`
}) })
let messageIndex = 5, lastMessage = 0, initSocket = false; let messageIndex = 5, lastMessage = 0, initSocket = false;
@ -51,7 +54,7 @@ function App() {
function logout() { function logout() {
//TODO 调用注销登录接口 //TODO 调用注销登录接口
localStorage.removeItem("chat-login") localStorage.removeItem(LOGIN_TOKEN_KEY)
setState({user: undefined}) setState({user: undefined})
} }
@ -88,7 +91,7 @@ function App() {
} }
function loadUserInfo() { function loadUserInfo() {
if (localStorage.getItem("chat-login")) { if (!localStorage.getItem(LOGIN_TOKEN_KEY)) {
return; return;
} }
info().then(user => { info().then(user => {
@ -147,7 +150,7 @@ function App() {
})(); })();
}; };
// 监听 // 监听
useEffect(loadUserInfo, []) useEffectOnce(loadUserInfo)
useEffect(() => { useEffect(() => {
if (messageList.length == 0) return; if (messageList.length == 0) return;
scrollToBottom(); scrollToBottom();
@ -203,16 +206,18 @@ function App() {
</>)} </>)}
</Button> </Button>
{state.user?.vip && {state.user?.vip &&
<div className="open-vip" onClick={() => setState({showVip: true})}>+&lt;</div>} <div className="open-vip" onClick={() => setState({showVip: true})}>+ &gt;</div>}
</div> </div>
</form> </form>
</div> </div>
</div> </div>
{state.showLogin && <Login {state.showLogin && <Login
onClose={(logged) => { onClose={(logged,data) => {
setState({showLogin: false}) setState({showLogin: false})
localStorage.setItem("chat-login", "yes") if(logged && data){
logged && loadUserInfo() localStorage.setItem(LOGIN_TOKEN_KEY, data.token)
loadUserInfo()
}
}} }}
/>} />}
{state.showVip && <Vip onClose={(opened) => { {state.showVip && <Vip onClose={(opened) => {

View File

@ -4,10 +4,10 @@ import IconClose from "./icons/IconClose";
import Button from "./Button"; import Button from "./Button";
import {useSetState, useCountDown} from "ahooks"; import {useSetState, useCountDown} from "ahooks";
import Checkbox from "./Checkbox"; import Checkbox from "./Checkbox";
import {login, sendCode} from "../services/api"; import {login, sendCode, UserModel} from "../services/api";
export type LoginProps = { export type LoginProps = {
onClose: (logged?: boolean) => void onClose: (logged?: boolean,user?: UserModel) => void
} }
const Login: React.FC<LoginProps> = (props) => { const Login: React.FC<LoginProps> = (props) => {
@ -45,8 +45,8 @@ const Login: React.FC<LoginProps> = (props) => {
return; return;
} }
setState({error: '', loginLoading: true}) setState({error: '', loginLoading: true})
login(data).then(() => { login(data).then((ret) => {
props.onClose(true) props.onClose(true,ret)
}).catch(error).finally(() => { }).catch(error).finally(() => {
setState({ setState({
loginLoading: false loginLoading: false

View File

@ -11,10 +11,11 @@ export type UserModel = {
export function login(data: any) { export function login(data: any) {
return post<UserModel>('/api/user/login', data) return post<UserModel>('/api/user/login', data)
} }
export function info() {
return get<UserModel>('/api/user/info')
}
export function info() {
const token = localStorage.getItem(APP_CONFIG.LOGIN_TOKEN_KEY)
return post<UserModel>('/api/user/info', {token})
}
export function sendCode(phone: string) { export function sendCode(phone: string) {
return post('/api/sendCode', {phone}) return post('/api/sendCode', {phone})

View File

@ -15,17 +15,21 @@ const Axios = axios.create({
baseURL: APP_CONFIG.API_PREFIX, baseURL: APP_CONFIG.API_PREFIX,
timeout: 20000, // 设置超时时长 timeout: 20000, // 设置超时时长
headers: { headers: {
'Content-Type': JSON_FORMAT, 'Content-Type': JSON_FORMAT
} }
}) })
// 请求前拦截 // 请求前拦截
// Axios.interceptors.request.use(config => { Axios.interceptors.request.use(config => {
// return config const token = localStorage.getItem(APP_CONFIG.LOGIN_TOKEN_KEY)
// }, err => { if (token) {
// return Promise.reject(err) config.headers['token'] = token;
// }) }
return config
}, err => {
return Promise.reject(err)
})
// //
// // 返回后拦截 // // 返回后拦截
// Axios.interceptors.response.use(res => { // Axios.interceptors.response.use(res => {

View File

@ -0,0 +1,27 @@
import {useEffect, useRef, useState} from "react"
export function useEffectOnce(effect:Function) {
const effectFn = useRef(effect)
const destroyFn = useRef<Function>()
const effectCalled = useRef(false)
const rendered = useRef(false)
const [, refresh] = useState(0)
if (effectCalled.current) {
rendered.current = true
}
useEffect(() => {
if (!effectCalled.current) {
destroyFn.current = effectFn.current()
effectCalled.current = true
}
refresh(1)
return () => {
if (rendered.current === false) return
if (destroyFn.current) destroyFn.current()
}
}, [])
}

1
src/vite-env.d.ts vendored
View File

@ -11,6 +11,7 @@ interface IAppConfigItem {
* *
*/ */
PUBLIC_PATH?: string PUBLIC_PATH?: string
LOGIN_TOKEN_KEY: string
} }
type IAPP_ENV = 'development' | 'test' | 'production' type IAPP_ENV = 'development' | 'test' | 'production'