实现refreshToken与accessToken
This commit is contained in:
parent
423ee48c85
commit
6dbbddcf5e
|
|
@ -1,5 +1,6 @@
|
|||
import { createRouter, createWebHistory } from "vue-router"
|
||||
import { useLoginStore } from "@/store/authentication/index"
|
||||
import cache from "@/utils/cache"
|
||||
const routes = [
|
||||
{ path: "/", redirect: "/home", meta: { requiresAuth: true } },
|
||||
{
|
||||
|
|
@ -77,14 +78,13 @@ const router = createRouter({
|
|||
|
||||
// // 全局前置守卫
|
||||
router.beforeEach((to, from, next) => {
|
||||
const loginStore = useLoginStore()
|
||||
|
||||
const token = cache.getItem("token")
|
||||
// 如果目标路由需要登录且用户未登录
|
||||
if (to.meta.requiresAuth && !loginStore.token) {
|
||||
if (to.meta.requiresAuth && !token) {
|
||||
next("/login") // 跳转到登录页
|
||||
}
|
||||
// 如果用户已登录但尝试访问登录页
|
||||
else if (to.path === "/login" && loginStore.token) {
|
||||
else if (to.path === "/login" && token) {
|
||||
next("/home") // 跳转到主页
|
||||
}
|
||||
// 其他情况正常放行
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
import http from "@/utils/http"
|
||||
|
||||
export function login(userInfo) {
|
||||
return http.post("/auth/login", userInfo)
|
||||
return http.post("/auth/login", userInfo, { withCredentials: true })
|
||||
}
|
||||
|
||||
export function refreshToken() {
|
||||
return http.post("/auth/refresh", {}, { withCredentials: true })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,10 +69,7 @@ export function getSocialCommunityList() {
|
|||
}
|
||||
|
||||
// 社交紧密团体中社团内的社团内部节点 从用户组中点击,只显示这两个用户的关系
|
||||
export function getSocialCommunityDetailFromUserGroup(
|
||||
relationId,
|
||||
time = "2024-05-16 16:56:04"
|
||||
) {
|
||||
export function getSocialCommunityDetailFromUserGroup(relationId, time = "2024-05-16 16:56:04") {
|
||||
return http.get(`/linkPrediction/user_detail?relationId=${relationId}&time=${time}`)
|
||||
}
|
||||
// 社交紧密团体的社团内部节点
|
||||
|
|
@ -110,3 +107,8 @@ export function getCharacterSocialCommunityDetailNodes(
|
|||
return http.get(`/linkPrediction/social/community_detail?groupIds=${ids}&dateTime=${time}`)
|
||||
}
|
||||
}
|
||||
|
||||
//点击边获取两用户交互的次数
|
||||
export function getInteractionCount(source, target) {
|
||||
return http.get(`/linkPrediction/interactionCount?source=${source}&target=${target}`)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,34 @@
|
|||
import { defineStore } from "pinia"
|
||||
import { login } from "@/service/api/authentication"
|
||||
import { login, refreshToken } from "@/service/api/authentication"
|
||||
import cache from "@/utils/cache"
|
||||
import router from "@/router"
|
||||
import { ElMessage } from "element-plus"
|
||||
const TOKEN_KEY = "token"
|
||||
export const useLoginStore = defineStore("loginStore", {
|
||||
state: () => ({
|
||||
token: cache.getItem(TOKEN_KEY) ?? ""
|
||||
token: cache.getItem("token") ?? ""
|
||||
}),
|
||||
actions: {
|
||||
setToken(accessToken) {
|
||||
this.token = accessToken
|
||||
cache.setItem("token", accessToken)
|
||||
},
|
||||
async loginForAccessToken(userInfo) {
|
||||
const res = await login(userInfo)
|
||||
if (res.code != 200) return
|
||||
this.token = res.data.accessToken
|
||||
cache.setItem(TOKEN_KEY, res.data.accessToken)
|
||||
this.setToken(res.data.accessToken)
|
||||
ElMessage.success("登录成功!")
|
||||
router.push("/navigation")
|
||||
},
|
||||
|
||||
async loginForRefreshToken() {
|
||||
const res = await refreshToken()
|
||||
console.log(res)
|
||||
if (res.code == 200) {
|
||||
this.setToken(res.data.accessToken)
|
||||
return true // 刷新成功
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ import {
|
|||
getSocialPostListByRelationId,
|
||||
getCharacterSocialCommunityNodes,
|
||||
getCharacterSocialCommunityStatistics,
|
||||
getCharacterSocialCommunityDetailNodes
|
||||
getCharacterSocialCommunityDetailNodes,
|
||||
getInteractionCount
|
||||
} from "@/service/api/linkPrediction"
|
||||
|
||||
import defaultAvatar from "@/assets/images/avatar/default.png"
|
||||
|
|
@ -209,6 +210,11 @@ export const useCharacterInteractionStore = defineStore("characterInteraction",
|
|||
...item,
|
||||
count: res.data[item.key]
|
||||
}))
|
||||
},
|
||||
async initInteractionCount(source, target) {
|
||||
const res = await getInteractionCount(source, target)
|
||||
if (res.code != 200) return
|
||||
return res.data
|
||||
}
|
||||
},
|
||||
persist: true // 开启持久化
|
||||
|
|
@ -415,7 +421,7 @@ export const useSocialGroupsStore = defineStore("socialGroups", {
|
|||
{ text: "立委", top: 57.5, left: 72.5, width: 49, height: 19, fontSize: 12, opacity: 0.6 },
|
||||
{ text: "國會", top: 60.5, left: 265.5, width: 49, height: 19, fontSize: 12, opacity: 0.7 },
|
||||
{ text: "两岸", top: 170.5, left: 287.5, width: 49, height: 19, fontSize: 12, opacity: 0.8 }
|
||||
],
|
||||
]
|
||||
}),
|
||||
actions: {
|
||||
// 互动行为相似列表数据
|
||||
|
|
@ -470,8 +476,8 @@ export const useSocialGroupsStore = defineStore("socialGroups", {
|
|||
) {
|
||||
customStatisticsObj.hiddenInteractionCount = 1
|
||||
// 创建一个Set来获取不重复的ids
|
||||
const uniqueIds = new Set(ids);
|
||||
customStatisticsObj.groupCount = uniqueIds.size;
|
||||
const uniqueIds = new Set(ids)
|
||||
customStatisticsObj.groupCount = uniqueIds.size
|
||||
}
|
||||
|
||||
this.statisticsDetailList = this.statisticsDetailList.map((item) => ({
|
||||
|
|
@ -681,6 +687,12 @@ export const useCharacterHiddenStore = defineStore("characterHidden", {
|
|||
this.communityDetailNodeList = res.data.userList
|
||||
this.timeList = Array.from(new Set(res.data.timeList))
|
||||
this.predictionUserIds = res.data.predictNodes
|
||||
},
|
||||
|
||||
async initInteractionCount(source, target) {
|
||||
const res = await getInteractionCount(source, target)
|
||||
if (res.code != 200) return
|
||||
return res.data
|
||||
}
|
||||
},
|
||||
persist: true // 开启持久化
|
||||
|
|
|
|||
|
|
@ -2,16 +2,16 @@ import axios from "axios"
|
|||
import cache from "./cache"
|
||||
import { ElMessage } from "element-plus"
|
||||
import router from "@/router"
|
||||
|
||||
import { useLoginStore } from "@/store/authentication/index"
|
||||
// 创建axios实例
|
||||
const service = axios.create({
|
||||
baseURL: import.meta.env.VITE_APP_BASE_API, // 从环境变量获取基础URL
|
||||
timeout: 10000 // 请求超时时间
|
||||
timeout: 10000, // 请求超时时间
|
||||
withCredentials: true
|
||||
})
|
||||
|
||||
//白名单
|
||||
const excludePath = new Set(["/login"])
|
||||
// 请求拦截器
|
||||
const excludePath = new Set(["/auth/login", "/auth/refresh"])
|
||||
service.interceptors.request.use(
|
||||
(config) => {
|
||||
const token = cache.getItem("token")
|
||||
|
|
@ -21,17 +21,14 @@ service.interceptors.request.use(
|
|||
return config
|
||||
},
|
||||
(error) => {
|
||||
// 对请求错误做些什么
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// 响应拦截器
|
||||
service.interceptors.response.use(
|
||||
(response) => {
|
||||
async (response) => {
|
||||
const res = response.data
|
||||
|
||||
// 根据业务状态码处理
|
||||
const loginStore = useLoginStore()
|
||||
if (res.code !== 200) {
|
||||
ElMessage({
|
||||
message: res.message || "Error",
|
||||
|
|
@ -39,29 +36,32 @@ service.interceptors.response.use(
|
|||
duration: 5 * 1000
|
||||
})
|
||||
|
||||
// 特殊状态码处理
|
||||
if (res.code === 401 || res.code === 403) {
|
||||
// 若token过期,或者token无效,或者未找到token,对页面中需要认证的接口都有效,使得重新登录
|
||||
import("@/store/authentication/index").then(({ useLoginStore }) => {
|
||||
useLoginStore().token = ""
|
||||
})
|
||||
cache.removeItem("token")
|
||||
router.push("/login")
|
||||
try {
|
||||
// 尝试刷新token
|
||||
const refreshed = await loginStore.loginForRefreshToken()
|
||||
if (refreshed) {
|
||||
// 刷新成功,更新请求头中的accessToken并重新发送请求
|
||||
response.config.headers.Authorization = `Bearer ${loginStore.token}`
|
||||
return service(response.config)
|
||||
}
|
||||
} catch (refreshError) {
|
||||
ElMessage({
|
||||
message: "会话已过期,请重新登录!",
|
||||
type: "error",
|
||||
duration: 5 * 1000
|
||||
})
|
||||
cache.removeItem("token")
|
||||
router.push("/login")
|
||||
return Promise.reject(new Error("Refresh token failed"))
|
||||
}
|
||||
}
|
||||
return res
|
||||
// return Promise.reject(new Error(res.message || "Error"))
|
||||
return Promise.reject(new Error(res.message || "Error")) //500会抛出该错
|
||||
} else {
|
||||
return res
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
if (error.status == 401 || error.status == 403) {
|
||||
cache.removeItem("token")
|
||||
import("@/store/authentication/index").then(({ useLoginStore }) => {
|
||||
useLoginStore().token = ""
|
||||
})
|
||||
router.push("/login")
|
||||
}
|
||||
ElMessage({
|
||||
message: error.message,
|
||||
type: "error",
|
||||
|
|
|
|||
|
|
@ -53,10 +53,31 @@ const handleGoback = () => {
|
|||
emit("click:goback", "CommunityNode")
|
||||
}
|
||||
|
||||
const handleClickNode = () => {
|
||||
chart.on("click", function (params) {
|
||||
const handleClickNodeOrLink = () => {
|
||||
chart.on("click", async function (params) {
|
||||
if (params.dataType == "node" && predictionUserIds.value.includes(params.data.id)) {
|
||||
//点击预测节点展示弹窗
|
||||
emit("click:openDialog", params.data)
|
||||
} else if (params.dataType == "edge") {
|
||||
//点击连线获取交互次数
|
||||
const { source, target } = params.data //获取该边的两头节点id
|
||||
const linkIndex = params.dataIndex
|
||||
const option = chart.getOption()
|
||||
const currentInteractionCount = await props.interactionStore.initInteractionCount(
|
||||
source,
|
||||
target
|
||||
)
|
||||
option.series[0].links[linkIndex].edge = currentInteractionCount
|
||||
chart.setOption(
|
||||
{
|
||||
series: [
|
||||
{
|
||||
links: option.series[0].links
|
||||
}
|
||||
]
|
||||
},
|
||||
false
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -157,8 +178,7 @@ const initChart = async () => {
|
|||
links.push({
|
||||
source: parentId,
|
||||
target: child.id,
|
||||
edge: child.isHidden ? 1 : 0,
|
||||
interactionTimes: child.interactionTime,
|
||||
edge: 0,
|
||||
lineStyle: {
|
||||
width: child.isHidden ? 7 : edgeWidth(child.interactionTime),
|
||||
color: child.isHidden ? props.interactionStore.predictionLineColor : "#37ACD7", // 无互动=灰色,有互动=黄色
|
||||
|
|
@ -267,7 +287,7 @@ const initChart = async () => {
|
|||
show: false,
|
||||
position: "middle",
|
||||
formatter: function (params) {
|
||||
return `${params.data.interactionTimes}次互动`
|
||||
return `${params.data.edge}次互动`
|
||||
},
|
||||
fontSize: 14
|
||||
},
|
||||
|
|
@ -381,7 +401,7 @@ const highLightUserNodes = (userIds) => {
|
|||
onMounted(() => {
|
||||
initChart()
|
||||
highLightUserNodes()
|
||||
handleClickNode()
|
||||
handleClickNodeOrLink()
|
||||
})
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
:model="ruleForm"
|
||||
status-icon
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
:label-width="null"
|
||||
class="demo-ruleForm"
|
||||
@submit.native.prevent="submitForm(ruleFormRef)"
|
||||
>
|
||||
|
|
@ -71,7 +71,6 @@ const submitForm = (formEl) => {
|
|||
if (valid) {
|
||||
const userInfo = toRaw(ruleForm)
|
||||
loginStore.loginForAccessToken(userInfo)
|
||||
} else {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -84,6 +83,7 @@ const submitForm = (formEl) => {
|
|||
border-radius: 7px;
|
||||
background-color: #fff;
|
||||
padding: 0 40px;
|
||||
|
||||
.demo-ruleForm {
|
||||
margin-top: 100px;
|
||||
height: 50%;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import LoginPanel from "./components/loginPanel.vue"
|
||||
import LoginPanel from "@/views/Login/components/loginPanel.vue"
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
|
@ -37,9 +37,10 @@ import LoginPanel from "./components/loginPanel.vue"
|
|||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
// 当视口 ≤ 1350px 时,固定宽度但高度自适应
|
||||
@media (max-width: 1350px) {
|
||||
width: 650px; // 固定宽度
|
||||
width: 750px; // 固定宽度
|
||||
}
|
||||
|
||||
// 当视口高度 ≤ 750px 时,固定高度并允许滚动
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user