feat: 前端用户信息迁移至localstorage

This commit is contained in:
meilin.huang
2023-09-16 17:07:48 +08:00
parent dd4ac390de
commit 72677e270d
20 changed files with 110 additions and 70 deletions

View File

@@ -15,7 +15,7 @@
"countup.js": "^2.7.0",
"cropperjs": "^1.5.11",
"echarts": "^5.4.0",
"element-plus": "^2.3.12",
"element-plus": "^2.3.14",
"jsencrypt": "^3.3.1",
"lodash": "^4.17.21",
"mitt": "^3.0.1",

View File

@@ -1,7 +1,7 @@
import router from '../router';
import Axios from 'axios';
import config from './config';
import { getSession } from './utils/storage';
import { getToken } from './utils/storage';
import { templateResolve } from './utils/string';
import { ElMessage } from 'element-plus';
@@ -50,7 +50,7 @@ const service = Axios.create({
service.interceptors.request.use(
(config: any) => {
// do something before request is sent
const token = getSession('token');
const token = getToken();
if (token) {
// 设置token
config.headers['Authorization'] = token;
@@ -143,8 +143,8 @@ function request(method: string, url: string, params: any = null, headers: any =
.request(query)
.then((res) => res)
.catch((e) => {
// 如果返回的code不为成功则会返回对应的错误msg则直接统一通知即可
if (e.msg) {
// 如果返回的code不为成功则会返回对应的错误msg则直接统一通知即可。忽略登录超时或没有权限的提示直接跳转至401页面
if (e.msg && e?.code != ResultEnum.NO_PERMISSION) {
notifyErrorMsg(e.msg);
}
return Promise.reject(e);
@@ -176,7 +176,7 @@ function del(url: string, params: any = null, headers: any = null, options: any
function getApiUrl(url: string) {
// 只是返回api地址而不做请求用在上传组件之类的
return baseUrl + url + '?token=' + getSession('token');
return baseUrl + url + '?token=' + getToken();
}
export default {

View File

@@ -1,14 +1,14 @@
import Config from './config';
import { ElNotification } from 'element-plus';
import SocketBuilder from './SocketBuilder';
import { getSession } from '@/common/utils/storage';
import { getToken } from '@/common/utils/storage';
export default {
/**
* 全局系统消息websocket
*/
sysMsgSocket() {
const token = getSession('token');
const token = getToken();
if (!token) {
return null;
}

View File

@@ -1,17 +1,58 @@
const TokenKey = 'token';
const UserKey = 'user';
// 获取请求token
export function getToken(): string {
return getLocal(TokenKey);
}
// 保存用户访问token
export function saveToken(token: string) {
setLocal(TokenKey, token);
}
// 获取登录用户基础信息
export function getUser() {
return getLocal(UserKey);
}
// 保存用户信息
export function saveUser(userinfo: any) {
setLocal(UserKey, userinfo);
}
// 获取是否开启水印
export function getUseWatermark() {
return getLocal('useWatermark');
}
export function saveUseWatermark(useWatermark: boolean) {
setLocal('useWatermark', useWatermark);
}
// 清楚用户相关的用户信息
export function clearUser() {
removeLocal(TokenKey);
removeLocal(UserKey);
}
// 1. localStorage
// 设置永久缓存
export function setLocal(key: string, val: any) {
window.localStorage.setItem(key, JSON.stringify(val));
}
// 获取永久缓存
export function getLocal(key: string) {
let json: any = window.localStorage.getItem(key);
return JSON.parse(json);
}
// 移除永久缓存
export function removeLocal(key: string) {
window.localStorage.removeItem(key);
}
// 移除全部永久缓存
export function clearLocal() {
window.localStorage.clear();
@@ -22,33 +63,20 @@ export function clearLocal() {
export function setSession(key: string, val: any) {
window.sessionStorage.setItem(key, JSON.stringify(val));
}
// 获取临时缓存
export function getSession(key: string) {
let json: any = window.sessionStorage.getItem(key);
return JSON.parse(json);
}
// 移除临时缓存
export function removeSession(key: string) {
window.sessionStorage.removeItem(key);
}
// 移除全部临时缓存
export function clearSession() {
clearUser();
window.sessionStorage.clear();
}
export function getUserInfo4Session() {
return getSession('userInfo');
}
export function setUserInfo2Session(userinfo: any) {
setSession('userInfo', userinfo);
}
// 获取是否开启水印
export function getUseWatermark4Session() {
return getSession('useWatermark');
}
export function setUseWatermark2Session(useWatermark: boolean) {
setSession('useWatermark', useWatermark);
}

View File

@@ -1,4 +1,4 @@
import { getUseWatermark4Session, getUserInfo4Session } from '@/common/utils/storage';
import { getUseWatermark, getUser } from '@/common/utils/storage';
import { dateFormat2 } from '@/common/utils/date';
// 页面添加水印效果
@@ -44,8 +44,8 @@ function del() {
const watermark = {
use: () => {
setTimeout(() => {
const userinfo = getUserInfo4Session();
if (userinfo && getUseWatermark4Session()) {
const userinfo = getUser();
if (userinfo && getUseWatermark()) {
set(`${userinfo.username} ${dateFormat2('yyyy-MM-dd HH:mm:ss', new Date())}`);
} else {
del();

View File

@@ -1,7 +1,7 @@
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
import { getSession, clearSession } from '@/common/utils/storage';
import { clearSession, getToken } from '@/common/utils/storage';
import { templateResolve } from '@/common/utils/string';
import { NextLoading } from '@/common/utils/loading';
import { dynamicRoutes, staticRoutes, pathMatch } from './route';
@@ -30,7 +30,7 @@ const router = createRouter({
// 前端控制路由:初始化方法,防止刷新时丢失
export function initAllFun() {
NextLoading.start(); // 界面 loading 动画开始执行
const token = getSession('token'); // 获取浏览器缓存 token 值
const token = getToken(); // 获取浏览器缓存 token 值
if (!token) {
// 无 token 停止执行下一步
return false;
@@ -49,7 +49,7 @@ export function initAllFun() {
// 后端控制路由:执行路由数据初始化
export async function initBackEndControlRoutesFun() {
NextLoading.start(); // 界面 loading 动画开始执行
const token = getSession('token'); // 获取浏览器缓存 token 值
const token = getToken(); // 获取浏览器缓存 token 值
if (!token) {
// 无 token 停止执行下一步
return false;
@@ -256,7 +256,7 @@ router.beforeEach(async (to, from, next) => {
to.meta.title = templateResolve(to.meta.title as string, to.query);
}
const token = getSession('token');
const token = getToken();
if ((to.path === '/login' || to.path == '/oauth2/callback') && !token) {
next();
NProgress.done();

View File

@@ -1,5 +1,5 @@
import { defineStore } from 'pinia';
import { getSession } from '@/common/utils/storage';
import { getUser } from '@/common/utils/storage';
export const useUserInfo = defineStore('userInfo', {
state: (): UserInfoState => ({
@@ -8,7 +8,7 @@ export const useUserInfo = defineStore('userInfo', {
actions: {
// 设置用户信息
async setUserInfo(data: object) {
const ui = getSession('userInfo');
const ui = getUser();
if (ui) {
this.userInfo = ui;
} else {

View File

@@ -83,7 +83,7 @@ import { resetRoute } from '@/router/index';
import { storeToRefs } from 'pinia';
import { useUserInfo } from '@/store/userInfo';
import { useThemeConfig } from '@/store/themeConfig';
import { clearSession, setLocal, getLocal, removeLocal } from '@/common/utils/storage';
import { clearUser, clearSession, setLocal, getLocal, removeLocal } from '@/common/utils/storage';
import UserNews from '@/views/layout/navBars/breadcrumb/userNews.vue';
import SearchMenu from '@/views/layout/navBars/breadcrumb/search.vue';
import mittBus from '@/common/utils/mitt';

View File

@@ -132,7 +132,7 @@ import { nextTick, onMounted, ref, toRefs, reactive, computed } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { ElMessage } from 'element-plus';
import { initRouter } from '@/router/index';
import { getSession, setSession, setUserInfo2Session, setUseWatermark2Session } from '@/common/utils/storage';
import { saveToken, saveUser, saveUseWatermark } from '@/common/utils/storage';
import { formatAxis } from '@/common/utils/format';
import openApi from '@/common/openApi';
import { RsaEncrypt } from '@/common/rsa';
@@ -142,6 +142,7 @@ import { useUserInfo } from '@/store/userInfo';
import QrcodeVue from 'qrcode.vue';
import { personApi } from '@/views/personal/api';
import { AccountUsernamePattern } from '@/common/pattern';
import { getToken } from '../../../common/utils/storage';
const rules = {
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
@@ -354,7 +355,7 @@ const loginResDeal = (loginRes: any) => {
};
// 存储用户信息到浏览器缓存
setUserInfo2Session(userInfos);
saveUser(userInfos);
// 1、请注意执行顺序(存储用户信息到vuex)
useUserInfo().setUserInfo(userInfos);
@@ -376,10 +377,10 @@ const loginResDeal = (loginRes: any) => {
// 登录成功后的跳转
const signInSuccess = async (accessToken: string = '') => {
if (!accessToken) {
accessToken = getSession('token');
accessToken = getToken();
}
// 存储 token 到浏览器缓存
setSession('token', accessToken);
saveToken(accessToken);
// 初始化路由
await initRouter();
@@ -405,7 +406,7 @@ const toIndex = async () => {
state.loading.signIn = true;
ElMessage.success(`${currentTimeInfo},欢迎回来!`);
if (await useWartermark()) {
setUseWatermark2Session(true);
saveUseWatermark(true);
}
}, 300);
};

View File

@@ -172,7 +172,7 @@ import { ref, toRefs, reactive, onMounted, defineAsyncComponent } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { dbApi } from './api';
import config from '@/common/config';
import { getSession } from '@/common/utils/storage';
import { getToken } from '@/common/utils/storage';
import { isTrue } from '@/common/assert';
import { Search as SearchIcon } from '@element-plus/icons-vue';
import { dateFormat } from '@/common/utils/date';
@@ -406,7 +406,7 @@ const dumpDbs = () => {
'href',
`${config.baseApiUrl}/dbs/${state.exportDialog.dbId}/dump?db=${state.exportDialog.value.join(',')}&type=${type}&extName=${
state.exportDialog.extName
}&token=${getSession('token')}`
}&token=${getToken()}`
);
a.click();
state.exportDialog.visible = false;

View File

@@ -92,7 +92,7 @@
import { nextTick, watch, onMounted, reactive, toRefs, ref, Ref } from 'vue';
import { storeToRefs } from 'pinia';
import { useThemeConfig } from '@/store/themeConfig';
import { getSession } from '@/common/utils/storage';
import { getToken } from '@/common/utils/storage';
import { isTrue, notBlank } from '@/common/assert';
import { format as sqlFormatter } from 'sql-formatter';
import config from '@/common/config';
@@ -148,7 +148,7 @@ const props = defineProps({
});
const { themeConfig } = storeToRefs(useThemeConfig());
const token = getSession('token');
const token = getToken();
let monacoEditor = {} as editor.IStandaloneCodeEditor;
const dbTableRef = ref(null) as Ref;

View File

@@ -124,7 +124,7 @@ import { formatByteSize } from '@/common/utils/format';
import { dbApi } from '../api';
import SqlExecBox from '../component/SqlExecBox';
import config from '@/common/config';
import { getSession } from '@/common/utils/storage';
import { getToken } from '@/common/utils/storage';
import { isTrue } from '@/common/assert';
const DbTableEdit = defineAsyncComponent(() => import('./DbTableEdit.vue'));
@@ -259,9 +259,7 @@ const dump = (db: string) => {
const a = document.createElement('a');
a.setAttribute(
'href',
`${config.baseApiUrl}/dbs/${props.dbId}/dump?db=${db}&type=${state.dumpInfo.type}&tables=${state.dumpInfo.tables.join(',')}&token=${getSession(
'token'
)}`
`${config.baseApiUrl}/dbs/${props.dbId}/dump?db=${db}&type=${state.dumpInfo.type}&tables=${state.dumpInfo.tables.join(',')}&token=${getToken()}`
);
a.click();
state.showDumpInfo = false;

View File

@@ -1,6 +1,6 @@
import Api from '@/common/Api';
import config from '@/common/config';
import { getSession } from '@/common/utils/storage';
import { getToken } from '@/common/utils/storage';
export const machineApi = {
// 获取权限列表
@@ -63,5 +63,5 @@ export const cronJobApi = {
};
export function getMachineTerminalSocketUrl(machineId: any) {
return `${config.baseWsUrl}/machines/${machineId}/terminal?token=${getSession('token')}`;
return `${config.baseWsUrl}/machines/${machineId}/terminal?token=${getToken()}`;
}

View File

@@ -272,7 +272,7 @@ import { ref, toRefs, reactive, onMounted, computed } from 'vue';
import { ElMessage, ElMessageBox, ElInput } from 'element-plus';
import { machineApi } from '../api';
import { getSession } from '@/common/utils/storage';
import { getToken } from '@/common/utils/storage';
import config from '@/common/config';
import { isTrue } from '@/common/assert';
import MachineFileContent from './MachineFileContent.vue';
@@ -285,7 +285,7 @@ const props = defineProps({
isFolder: { type: Boolean, default: true },
});
const token = getSession('token');
const token = getToken();
const folderUploadRef: any = ref();
const folderType = 'd';

View File

@@ -179,7 +179,7 @@ import { dateFormat } from '@/common/utils/date';
import { storeToRefs } from 'pinia';
import { useUserInfo } from '@/store/userInfo';
import config from '@/common/config';
import { getSession } from '@/common/utils/storage';
import { getToken } from '@/common/utils/storage';
const { userInfo } = storeToRefs(useUserInfo());
const state = reactive({
@@ -248,7 +248,7 @@ const bindOAuth2 = () => {
var iLeft = (window.screen.width - 10 - width) / 2; //获得窗口的水平位置;
// 小窗口打开oauth2鉴权
let oauthWindow = window.open(
config.baseApiUrl + '/auth/oauth2/bind?token=' + getSession('token'),
config.baseApiUrl + '/auth/oauth2/bind?token=' + getToken(),
'oauth2',
`height=${height},width=${width},top=${iTop},left=${iLeft},location=no`
);

View File

@@ -49,6 +49,7 @@ const viteConfig: UserConfig = {
manualChunks: {
vue: ['vue', 'vue-router', 'pinia'],
echarts: ['echarts'],
monaco: ['monaco-editor'],
},
},
},

View File

@@ -804,10 +804,10 @@ echarts@^5.4.0:
tslib "2.3.0"
zrender "5.4.0"
element-plus@^2.3.12:
version "2.3.12"
resolved "https://registry.npmmirror.com/element-plus/-/element-plus-2.3.12.tgz#d3c91d0c701b2b3e67d06a351cb0c42dcc46460e"
integrity sha512-fAWpbKCyt+l1dsqSNPOs/F/dBN4Wp5CGAyxbiS5zqDwI4q3QPM+LxLU2h3GUHMIBtMGCvmsG98j5HPMkTKkvcA==
element-plus@^2.3.14:
version "2.3.14"
resolved "https://registry.npmmirror.com/element-plus/-/element-plus-2.3.14.tgz#302a23916b0c3375fcf4b927d7b94483dac13e1b"
integrity sha512-9yvxUaU4jXf2ZNPdmIxoj/f8BG8CDcGM6oHa9JIqxLjQlfY4bpzR1E5CjNimnOX3rxO93w1TQ0jTVt0RSxh9kA==
dependencies:
"@ctrl/tinycolor" "^3.4.1"
"@element-plus/icons-vue" "^2.0.6"

View File

@@ -23,9 +23,28 @@ type Client struct {
ReadMsgHander ReadMsgHandlerFunc // 读取消息处理函数
}
func NewClient(userId UserId, socket *websocket.Conn) *Client {
cli := &Client{
ClientId: stringx.Rand(16),
UserId: userId,
WsConn: socket,
}
return cli
}
func (c *Client) WithReadHandlerFunc(readMsgHandlerFunc ReadMsgHandlerFunc) *Client {
c.ReadMsgHander = readMsgHandlerFunc
return c
}
// 读取ws客户端消息
func (c *Client) Read() {
go func() {
for {
if c.WsConn == nil {
return
}
messageType, data, err := c.WsConn.ReadMessage()
if err != nil {
if messageType == -1 && websocket.IsCloseError(err, websocket.CloseGoingAway, websocket.CloseNormalClosure, websocket.CloseNoStatusReceived) {
@@ -72,13 +91,3 @@ func (c *Client) WriteMsg(msg *Msg) error {
func (c *Client) Ping() error {
return c.WsConn.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(time.Second))
}
func NewClient(userId UserId, socket *websocket.Conn) *Client {
cli := &Client{
ClientId: stringx.Rand(16),
UserId: userId,
WsConn: socket,
}
return cli
}

View File

@@ -141,8 +141,10 @@ func (manager *ClientManager) doConnect(client *Client) {
// 处理断开连接
func (manager *ClientManager) doDisconnect(client *Client) {
//关闭连接
_ = client.WsConn.Close()
client.WsConn = nil
if client.WsConn != nil {
_ = client.WsConn.Close()
client.WsConn = nil
}
manager.delClient4Map(client)
logx.Debugf("WS客户端已断开: uid=%d, count=%d", client.UserId, Manager.Count())
}

View File

@@ -23,6 +23,7 @@ func init() {
// 添加ws客户端
func AddClient(userId uint64, conn *websocket.Conn) *Client {
cli := NewClient(UserId(userId), conn)
cli.Read()
Manager.AddClient(cli)
return cli
}