Ver Fonte

更新了token的刷新逻辑;修复了当更新游戏信息时,顶部导航栏的下拉框没有同步的BUG

fxs há 8 meses atrás
pai
commit
52198f67f5

+ 4 - 2
src/components/common/Dialog.vue

@@ -2,7 +2,7 @@
  * @Author: fxs bjnsfxs@163.com
  * @Date: 2024-09-04 11:21:05
  * @LastEditors: fxs bjnsfxs@163.com
- * @LastEditTime: 2024-09-25 17:56:27
+ * @LastEditTime: 2024-10-09 15:51:28
  * @FilePath: \Game-Backstage-Management-System\src\components\common\Dialog.vue
  * @Description: 
  * 
@@ -62,12 +62,14 @@ const closeDialog = () => {
 // 表单添加
 const addForm = () => {
   dialogConfigInfo.reqConfig.url = addUrl.value
+  dialogConfig.type = 0
   dialogConfig.dialogVisible = true
 }
 
 // 表单修改
 const editForm = (row: any, updateURL?: string) => {
   dialogConfig.dialogVisible = true
+  dialogConfig.type = 1
   if (updateURL) {
     updateUrl.value = updateURL
     dialogConfigInfo.reqConfig.url = updateUrl.value
@@ -97,7 +99,7 @@ const encrypt = (fields: string, useFormField: boolean, encryptMsg: Array<string
 }
 
 const subForm = (FormData: any) => {
-  emits('formSubmit', FormData)
+  emits('formSubmit', FormData, dialogConfig.type)
 }
 
 defineExpose({

+ 1 - 1
src/components/dataAnalysis/DropDownSelection.vue

@@ -2,7 +2,7 @@
  * @Author: fxs bjnsfxs@163.com
  * @Date: 2024-08-23 14:42:47
  * @LastEditors: fxs bjnsfxs@163.com
- * @LastEditTime: 2024-09-28 16:53:47
+ * @LastEditTime: 2024-10-09 16:18:29
  * @FilePath: \Game-Backstage-Management-System\src\components\dataAnalysis\DropDownSelection.vue
  * @Description: 下拉选择框,可用于分类字段或者切换平台等
  * 

+ 41 - 37
src/hooks/useRequest.ts

@@ -2,7 +2,7 @@
  * @Author: fxs bjnsfxs@163.com
  * @Date: 2024-08-20 17:24:06
  * @LastEditors: fxs bjnsfxs@163.com
- * @LastEditTime: 2024-09-18 15:28:50
+ * @LastEditTime: 2024-10-09 14:02:35
  * @FilePath: \Game-Backstage-Management-System\src\hooks\useRequest.ts
  * @Description:
  *
@@ -16,61 +16,64 @@ import type { AxiosResponse } from 'axios'
 import type { ResponseInfo } from '@/types/res'
 
 export function useRequest() {
-  let baseIp = ''
-  // 根据环境不同,切换不同的IP
+  let baseURL = ''
   if (import.meta.env.MODE === 'development') {
-    // baseIp = 'http://service.ichunhao.cn' // 正式库
-    baseIp = 'http://server.ichunhao.cn' // 测试服
+    baseURL = 'http://server.ichunhao.cn'
   } else {
-    baseIp = 'http://service.ichunhao.cn' // 正式库
+    baseURL = 'http://service.ichunhao.cn'
   }
-  // const baseIp = 'http://192.168.1.139:8000' // 本地
 
   const AllApi = {
     // mock: `http://127.0.0.1:8003/mock`,
     mockEvent: `http://127.0.0.1:8003/mockEvent`,
-    mockDate: `http://127.0.0.1:8003/mockDate`,
+    mockTest: `http://127.0.0.1:8003/test`,
 
-    getGameTable: `${baseIp}/user/getGidConfig`, // 获取游戏列表
-    getUserTable: `${baseIp}/user/userList`, // 获取用户列表
-    addGame: `${baseIp}/user/addGidConfig`, // 添加/修改 游戏配置
-    userLogin: `${baseIp}/user/login`, // 登录
-    addOption: `${baseIp}/user/addUserOption`, // 添加/修改 权限
-    addUserToBlack: `${baseIp}/user/addUserToBlackList`, // 封禁用户
-    deleteUserToBlack: `${baseIp}/user/deleteUserToBlackList`, // 解封用户
-    getInterfaceInfo: `${baseIp}/user/getInterfaceInfo`, // 拿到所有接口的信息
-    getInterfaceDataByDay: `${baseIp}/user/getInterfaceDataByDay`, //获取接口的请求频次 (按天)
-    gerRefreshToken: `${baseIp}/user/refreshToken`, // 刷新token
-    getOverViewData: `${baseIp}/user/overview`, // 总览数据
+    getGameTable: `/user/getGidConfig`, // 获取游戏列表
+    getUserTable: `/user/userList`, // 获取用户列表
+    addGame: `/user/addGidConfig`, // 添加/修改 游戏配置
+    userLogin: `/user/login`, // 登录
+    addOption: `/user/addUserOption`, // 添加/修改 权限
+    addUserToBlack: `/user/addUserToBlackList`, // 封禁用户
+    deleteUserToBlack: `/user/deleteUserToBlackList`, // 解封用户
+    getInterfaceInfo: `/user/getInterfaceInfo`, // 拿到所有接口的信息
+    getInterfaceDataByDay: `/user/getInterfaceDataByDay`, //获取接口的请求频次 (按天)
+    getRefreshToken: `/user/refreshToken`, // 刷新token
+    getOverViewData: `/user/overview`, // 总览数据
 
     // 数据分析相关URL
-    timeDistributionData: `${baseIp}/user/timeDistributionData`, //用户概览 -时段分布
-    userSummary: `${baseIp}/user/summary`, //用户概览 -总览
-    userMouthDistributionData: `${baseIp}/user/mouthDistributionData`, //用户概览 -30日趋势
-    userTrendsOverview: `${baseIp}/user/userTrendsOverview`, //用户趋势 -总览
-    userDataTrades: `${baseIp}/user/dataTrades`, //用户趋势 -数据趋势
-    userDataTradesDetail: `${baseIp}/user/dataTradesDetail`, //用户趋势 -数据趋势详情
-    userRemainDataBydDay: `${baseIp}/user/remainDataBydDay`, //用户留存数据
+    timeDistributionData: `/user/timeDistributionData`, //用户概览 -时段分布
+    userSummary: `/user/summary`, //用户概览 -总览
+    userMouthDistributionData: `/user/mouthDistributionData`, //用户概览 -30日趋势
+    userTrendsOverview: `/user/userTrendsOverview`, //用户趋势 -总览
+    userDataTrades: `/user/dataTrades`, //用户趋势 -数据趋势
+    userDataTradesDetail: `/user/dataTradesDetail`, //用户趋势 -数据趋势详情
+    userRemainDataBydDay: `/user/remainDataBydDay`, //用户留存数据
 
     // 事件相关
     // 事件
-    gameActionList: `${baseIp}/user/gameActionList`, // 游戏事件列表
-    gameActionDetail: `${baseIp}/user/gameActionDetail`, // 事件详情
-    updateGameAction: `${baseIp}/user/updateGameAction`, // 更新游戏事件
-    setGameAction: `${baseIp}/user/setGameAction`, // 新增事件
+    gameActionList: `/user/gameActionList`, // 游戏事件列表
+    gameActionDetail: `/user/gameActionDetail`, // 事件详情
+    updateGameAction: `/user/updateGameAction`, // 更新游戏事件
+    setGameAction: `/user/setGameAction`, // 新增事件
 
     // 事件参数
-    gameActionOptionList: `${baseIp}/user/gameActionOptionList`, // 获取事件参数列表
-    addGameActionOption: `${baseIp}/user/addGameActionOption`, // 新增事件参数
-    updateGameActionOption: `${baseIp}/user/updateGameActionOption`, // 更新事件参数
-    deleteGameActionOption: `${baseIp}/user/deleteGameActionOption`, // 删除事件参数
+    gameActionOptionList: `/user/gameActionOptionList`, // 获取事件参数列表
+    addGameActionOption: `/user/addGameActionOption`, // 新增事件参数
+    updateGameActionOption: `/user/updateGameActionOption`, // 更新事件参数
+    deleteGameActionOption: `/user/deleteGameActionOption`, // 删除事件参数
 
     // 事件分析
-    userActionDetailDistribution: `${baseIp}/user/userActionDetailDistribution`, // 事件统计趋势图
-    userActionDetail: `${baseIp}/user/userActionDetail`, // 事件统计详情
-    userActionList: `${baseIp}/user/userActionList` // 游戏事件统计列表
+    userActionDetailDistribution: `/user/userActionDetailDistribution`, // 事件统计趋势图
+    userActionDetail: `/user/userActionDetail`, // 事件统计详情
+    userActionList: `/user/userActionList` // 游戏事件统计列表
   }
 
+  /**
+   * @description: 根据返回码给出提示
+   * @param {AxiosResponse} data 返回的数据
+   * @param {string} kind 请求类型
+   * @return {*}
+   */
   const analysisResCode = (data: AxiosResponse, kind?: string): Promise<ResponseInfo> => {
     return new Promise((resolve, reject) => {
       let info = JSON.parse(JSON.stringify(data)) as ResponseInfo
@@ -101,6 +104,7 @@ export function useRequest() {
 
   return {
     AllApi,
+    baseURL,
     analysisResCode
   }
 }

+ 1 - 1
src/router/index.ts

@@ -2,7 +2,7 @@
  * @Author: fxs bjnsfxs@163.com
  * @Date: 2024-08-20 14:06:49
  * @LastEditors: fxs bjnsfxs@163.com
- * @LastEditTime: 2024-09-06 16:59:23
+ * @LastEditTime: 2024-10-09 12:07:47
  * @FilePath: \Game-Backstage-Management-System\src\router\index.ts
  * @Description:
  *

+ 1 - 2
src/stores/useCommon.ts

@@ -2,7 +2,7 @@
  * @Author: fxs bjnsfxs@163.com
  * @Date: 2024-08-28 11:46:10
  * @LastEditors: fxs bjnsfxs@163.com
- * @LastEditTime: 2024-09-28 17:10:24
+ * @LastEditTime: 2024-10-09 15:06:30
  * @FilePath: \Game-Backstage-Management-System\src\stores\useCommon.ts
  * @Description:通用的store,在多个页面均会使用
  *
@@ -37,7 +37,6 @@ export const useCommonStore = defineStore('commonStore', () => {
   // 同上
   let tempPf = getLocalInfo('tempMultipleChioce', 'pf')
   tempPf = tempPf ? tempPf : [selectInfo.pf[0]]
-
   // 临时使用的多选pf,为了不与selectInfo冲突
   // pf初始化的时候更seleinfo的一致,但是后续的修改不会影响selectInfo
   const tempMultipleChioce = reactive<SelectInfo>({

+ 3 - 2
src/utils/axios/auth.ts

@@ -2,7 +2,7 @@
  * @Author: fxs bjnsfxs@163.com
  * @Date: 2024-08-21 11:12:21
  * @LastEditors: fxs bjnsfxs@163.com
- * @LastEditTime: 2024-08-31 10:59:37
+ * @LastEditTime: 2024-10-09 10:05:08
  * @FilePath: \Game-Backstage-Management-System\src\utils\axios\auth.ts
  * @Description:
  *
@@ -14,7 +14,8 @@ import { MessageType } from '@/types/res'
 export const authToken = () => {
   return new Promise((reslove, reject) => {
     let refreshToken = localStorage.getItem('refreshToken')
-    if (refreshToken) {
+    let token = localStorage.getItem('token')
+    if (refreshToken || token) {
       reslove(true)
     } else {
       ElMessage({

+ 63 - 32
src/utils/axios/axiosInstance.ts

@@ -2,7 +2,7 @@
  * @Author: fxs bjnsfxs@163.com
  * @Date: 2024-08-20 17:18:52
  * @LastEditors: fxs bjnsfxs@163.com
- * @LastEditTime: 2024-09-09 10:58:26
+ * @LastEditTime: 2024-10-09 18:17:34
  * @FilePath: \Game-Backstage-Management-System\src\utils\axios\axiosInstance.ts
  * @Description:
  *
@@ -13,50 +13,81 @@ import router from '@/router'
 import { ElMessage } from 'element-plus'
 import { useRequest } from '@/hooks/useRequest'
 import { MessageType } from '@/types/res'
+import { getToken, refreshToken, setToken } from '../token/token'
+
+const { baseURL } = useRequest()
 
-const { AllApi } = useRequest()
 // 创建axios实例
-const axiosInstance = axios.create()
-// 请求拦截器
-axiosInstance.interceptors.request.use(
-  function (config) {
-    // console.log(config);
-    if (config.url === AllApi.gerRefreshToken) {
-      let refreshToken = localStorage.getItem('refreshToken')
-      if (refreshToken) {
-        config.headers.Authorization = refreshToken
-      }
-    } else if (config.url !== AllApi.userLogin) {
-      let token = localStorage.getItem('token')
+const axiosInstance = axios.create({
+  baseURL,
+  headers: {
+    Authorization: `${getToken()}`
+  }
+})
 
-      if (token) {
-        config.headers.Authorization = token
-      }
-    }
+let isRefreshing = false // 是否正在刷新token
+let requestQueue: any[] = [] // 存储请求队列
 
-    // 在发送请求之前做些什么
-    return config
-  },
-  function (error) {
-    // 对请求错误做些什么
-    return Promise.reject(error)
-  }
-)
 // 添加响应拦截器
 axiosInstance.interceptors.response.use(
-  function (response) {
-    // 对响应数据做点什么
-    if (response.data.code === -1) {
-      localStorage.removeItem('token')
-      localStorage.removeItem('refreshToken')
+  async function (response) {
+    const { code } = response.data
 
+    // -2是token为空的情况
+    if (code === -2) {
       ElMessage({
         type: MessageType.Warning,
-        message: '登录已过期,请重新登陆',
+        message: '请先登录',
         duration: 1500
       })
       router.push('/login')
     }
+    // -1是token过期的情况
+    if (code === -1) {
+      const config = response.config // 保存一下这一次的请求,等token刷新成功之后重新请求
+
+      if (!isRefreshing) {
+        isRefreshing = true
+        return await refreshToken()
+          .then((res) => {
+            if (res.data.code === 0) {
+              const token = JSON.parse(JSON.stringify(res.data.data.token))
+              setToken(token)
+              config.headers.Authorization = token // 将本次请求的token替换成新的token
+              requestQueue.forEach((cb) => cb(token)) // 将队列中的请求重新发起
+              requestQueue = []
+              return axiosInstance(config)
+            } else {
+              ElMessage({
+                type: MessageType.Warning,
+                message: '登录已过期,请重新登陆',
+                duration: 1500
+              })
+              router.push('/login')
+            }
+          })
+          .catch((err) => {
+            console.log(err)
+            ElMessage({
+              type: MessageType.Warning,
+              message: '登录已过期,请重新登陆',
+              duration: 1500
+            })
+            router.push('/login')
+          })
+          .finally(() => {
+            isRefreshing = false
+          })
+      } else {
+        // 如果正在刷新token,将本次请求加入队列,等token刷新成功之后重新发起请求
+        return new Promise((resolve) => {
+          requestQueue.push((token: string) => {
+            config.headers.Authorization = token
+            resolve(axiosInstance(config))
+          })
+        })
+      }
+    }
     return response.data
   },
   function (error) {

+ 1 - 1
src/utils/table/table.ts

@@ -6,7 +6,7 @@ const { AllApi } = useRequest()
 // 拿到所有游戏的信息
 export const getAllGameInfo = async () => {
   try {
-    const tableStore = useTableStore() // 这一句不要直接卸载函数外面,会导致在pinia挂载之前被调用
+    const tableStore = useTableStore() // 这一句不要直接写在函数外面,会导致在pinia挂载之前被调用
 
     if (tableStore.allGameInfo.length) return tableStore.allGameInfo
     else {

+ 51 - 5
src/utils/token/token.ts

@@ -1,13 +1,59 @@
+import { useRequest } from '@/hooks/useRequest'
+import axios from 'axios'
+const { AllApi, baseURL } = useRequest()
+
+const TokenKey = 'token' // token的key
+const RefreshTokenKey = 'refreshToken' // 刷新token的key
+
+/**
+ * @description: 获取token
+ * @return {*}
+ */
 const getToken = () => {
-  return localStorage.getItem('token')
+  return localStorage.getItem(TokenKey)
 }
 
+/**
+ * @description: 设置token
+ * @param {string} token token
+ * @return {*}
+ */
 const setToken = (token: string) => {
-  localStorage.setItem('token', token)
+  localStorage.setItem(TokenKey, token)
+}
+
+/**
+ * @description: 获取刷新Token
+ * @return {*}
+ */
+const getrefreshToken = () => {
+  return localStorage.getItem(RefreshTokenKey)
+}
+
+/**
+ * @description: 设置刷新Token
+ * @param {string} refreshToken 刷新token
+ * @return {*}
+ */
+const setRefreshToken = (refreshToken: string) => {
+  localStorage.setItem(RefreshTokenKey, refreshToken)
 }
 
-const setRefreshToken = (token: string) => {
-  localStorage.setItem('refreshToken', token)
+/**
+ * @description: 刷新Token
+ * @return {*}
+ */
+const refreshToken = async () => {
+  // 这里不要用实例去请求,如果refreshtoken也返回-1的话,会导致程序卡死
+  return await axios.post(
+    `${baseURL}${AllApi.getRefreshToken}`,
+    {},
+    {
+      headers: {
+        Authorization: `${getrefreshToken()}`
+      }
+    }
+  )
 }
 
-export { getToken, setToken, setRefreshToken }
+export { getToken, setToken, getrefreshToken, setRefreshToken, refreshToken }

+ 15 - 5
src/views/Home/InfoManage/GameManageView.vue

@@ -237,11 +237,21 @@ const handleEdit = (row: any) => {
   gameDialogRef.value.editForm(row)
 }
 
-const formSub = (formData: any) => {
-  allGameInfo.push({
-    gid: formData.gid,
-    gameName: formData.gameName
-  })
+const formSub = (formData: any, type: number) => {
+  console.log(type)
+  if (type === 0) {
+    allGameInfo.push({
+      gid: formData.gid,
+      gameName: formData.gameName
+    })
+  } else {
+    let game = allGameInfo.find((item) => item.gid === formData.gid)
+    if (game) {
+      console.log(formData.gameName)
+      game.gameName = formData.gameName
+    }
+  }
+
   gameTableRef.value?.getData()
 }
 

+ 45 - 25
src/views/Index.vue

@@ -2,7 +2,7 @@
  * @Author: fxs bjnsfxs@163.com
  * @Date: 2024-08-20 14:06:49
  * @LastEditors: fxs bjnsfxs@163.com
- * @LastEditTime: 2024-09-28 16:48:09
+ * @LastEditTime: 2024-10-09 16:31:29
  * @FilePath: \Game-Backstage-Management-System\src\views\Index.vue
  * @Description: 
  * 
@@ -154,29 +154,35 @@ watch(
  * @return {*}
  */
 const getGameInfo = () => {
-  getAllGameInfo().then((data) => {
-    if (data) {
-      data.map((item) => {
-        allGameInfo.push({
-          gid: item.gid,
-          gameName: item.gameName
-        })
-        gameSelectInfo.optionsList.push({
-          value: item.gid,
-          label: item.gameName
+  getAllGameInfo()
+    .then((data) => {
+      if (data) {
+        allGameInfo.splice(0, allGameInfo.length)
+        gameSelectInfo.optionsList.splice(0, gameSelectInfo.optionsList.length)
+        data.map((item) => {
+          allGameInfo.push({
+            gid: item.gid,
+            gameName: item.gameName
+          })
+          gameSelectInfo.optionsList.push({
+            value: item.gid,
+            label: item.gameName
+          })
         })
-      })
-      gameSelectInfo.defaultSelect = data[0].gid
-      // 去找本地的gid,如果有,就赋值,否则用请求回来的第一个gid
+        gameSelectInfo.defaultSelect = data[0].gid
+        // 去找本地的gid,如果有,就赋值,否则用请求回来的第一个gid
 
-      changeGame(selectInfo.gid)
-      gameSelectInfo.defaultSelect = selectInfo.gid
+        changeGame(selectInfo.gid)
+        gameSelectInfo.defaultSelect = selectInfo.gid
 
-      loadingState.value = true
-    } else {
-      throw new Error('游戏信息获取失败')
-    }
-  })
+        loadingState.value = true
+      } else {
+        throw new Error('游戏信息获取失败')
+      }
+    })
+    .catch((err) => {
+      console.log(err)
+    })
 }
 
 /**
@@ -195,11 +201,25 @@ const watchLoadingState = watch(
     if (newval) {
       watchGameListChange = watch(
         () => allGameInfo,
-        (newVal) => {
-          gameSelectInfo.optionsList.push({
-            value: newVal[newVal.length - 1].gid,
-            label: newVal[newVal.length - 1].gameName
+        (newGameInfo: Array<any>) => {
+          gameSelectInfo.optionsList.splice(0, gameSelectInfo.optionsList.length)
+          newGameInfo.forEach((item) => {
+            gameSelectInfo.optionsList.push({
+              value: item.gid,
+              label: item.gameName
+            })
           })
+          // getGameInfo()
+          // newGameInfo.map((item) => console.log(item))
+          // console.log(...newGameInfo)
+          // gameSelectInfo.optionsList.splice(0, gameSelectInfo.optionsList.length, ...newGameInfo)
+          // if (newGameInfo.length > oldGameInfo.length) {
+          //   gameSelectInfo.optionsList.push({
+          //     value: newGameInfo[newGameInfo.length - 1].gid,
+          //     label: newGameInfo[newGameInfo.length - 1].gameName
+          //   })
+          // }else{
+          // }
         },
         { deep: true }
       )

+ 6 - 2
src/views/Login/LoginView.vue

@@ -7,6 +7,7 @@ import axiosInstance from '@/utils/axios/axiosInstance'
 import MyButton from '@/components/form/MyButton.vue'
 import MyInput from '@/components/form/MyInput.vue'
 import { initLoadResouce } from '@/utils/resource'
+import { setToken, setRefreshToken } from '@/utils/token/token'
 
 const { AllApi, analysisResCode } = useRequest()
 
@@ -31,8 +32,11 @@ const userLogin = () => {
         let result = JSON.parse(JSON.stringify(data))
         analysisResCode(result, 'login')
           .then(() => {
-            localStorage.setItem('token', result.token)
-            localStorage.setItem('refreshToken', result.refreshToken)
+            setToken(result.token)
+            setRefreshToken(result.refreshToken)
+            // localStorage.setItem('token', result.token)
+            // localStorage.setItem('refreshToken', result.refreshToken)
+            axiosInstance.defaults.headers['Authorization'] = result.token // 需要在这里设置,不然又会触发拦截器
             router.push('/')
           })
           .catch((err) => {