Quellcode durchsuchen

登录失效自动返回登录页

handy vor 1 Monat
Ursprung
Commit
57f0ccd3a7
4 geänderte Dateien mit 50 neuen und 9 gelöschten Zeilen
  1. 30 5
      src/App.vue
  2. 7 2
      src/api/location.ts
  3. 12 2
      src/components/LoginModal.vue
  4. 1 0
      src/utils/auth.ts

+ 30 - 5
src/App.vue

@@ -3,13 +3,18 @@
     <LoginModal
       :visible="showLoginModal"
       @success="handleLoginSuccess"
+      @environment-change="handleEnvironmentChange"
       @cancel="handleLoginCancel"
     />
 
-    <header class="header">
+    <header
+      v-if="!showLoginModal"
+      class="header"
+    >
       <h1 class="title">
         {{ systemTitle }}
-        <span class="title-meta">库位 <span class="title-meta-value">{{ availableLocationsCount }}/{{ locations.length }}</span></span>
+        <span class="title-meta">库位
+          <span class="title-meta-value">{{ availableLocationsCount }}/{{ locations.length }}</span></span>
         <span class="title-fill-rate">
           <span
             class="title-meta title-fill-rate-item"
@@ -321,7 +326,10 @@
       </div>
     </div>
 
-    <main class="main-content">
+    <main
+      v-if="!showLoginModal"
+      class="main-content"
+    >
       <div
         v-if="loading"
         class="loading"
@@ -375,7 +383,7 @@ import type { LocationAttributeCode, LocationResourceDataVO } from './types'
 import WarehouseMap from './components/WarehouseMap.vue'
 import LoginModal from './components/LoginModal.vue'
 import { config } from './config'
-import { getApiEnvironment, isAuthenticated, removeToken } from './utils/auth'
+import { AUTH_INVALID_EVENT, getApiEnvironment, isAuthenticated, removeToken } from './utils/auth'
 
 const LEVEL_STORAGE_KEY = 'warehouse-map.current-level'
 const REFRESH_INTERVAL_STORAGE_KEY = 'warehouse-map.refresh-interval-ms'
@@ -791,6 +799,10 @@ const handleLoginCancel = () => {
   // 不允许取消登录,必须登录才能使用
 }
 
+const handleEnvironmentChange = (environment: 'sit' | 'prod') => {
+  currentEnvironment.value = environment
+}
+
 const handleLogout = () => {
   if (refreshTimer !== null) {
     window.clearTimeout(refreshTimer)
@@ -804,11 +816,24 @@ const handleLogout = () => {
   showLoginModal.value = true
 }
 
+const handleAuthInvalid = () => {
+  if (refreshTimer !== null) {
+    window.clearTimeout(refreshTimer)
+    refreshTimer = null
+  }
+  locations.value = []
+  hasLoadedOnce.value = false
+  loading.value = false
+  refreshing.value = false
+  showLoginModal.value = true
+}
+
 onMounted(() => {
   countdownTimer = window.setInterval(() => {
     now.value = Date.now()
   }, 1000)
   document.addEventListener('mousedown', handleDocumentClick)
+  window.addEventListener(AUTH_INVALID_EVENT, handleAuthInvalid)
 
   if (!isAuthenticated()) {
     showLoginModal.value = true
@@ -834,6 +859,7 @@ onBeforeUnmount(() => {
     window.clearInterval(countdownTimer)
   }
   document.removeEventListener('mousedown', handleDocumentClick)
+  window.removeEventListener(AUTH_INVALID_EVENT, handleAuthInvalid)
 })
 </script>
 
@@ -1270,7 +1296,6 @@ onBeforeUnmount(() => {
   transform: translateX(16px);
 }
 
-
 .level-select:hover,
 .level-select:focus {
   background: var(--input-hover-bg);

+ 7 - 2
src/api/location.ts

@@ -1,6 +1,6 @@
 import axios from 'axios'
 import type { ApiResponse, LocationRequest, LocationResourceDataVO } from '../types'
-import { getApiBaseUrl, getToken } from '../utils/auth'
+import { AUTH_INVALID_EVENT, getApiBaseUrl, getToken, removeToken } from '../utils/auth'
 
 const apiClient = axios.create({
   timeout: 10000,
@@ -28,7 +28,12 @@ apiClient.interceptors.request.use(
 // 响应拦截器:处理业务错误
 apiClient.interceptors.response.use(
   (response) => {
-    const { code, message } = response.data
+    const { code, message } = response.data || {}
+    if (code === 600) {
+      removeToken()
+      window.dispatchEvent(new CustomEvent(AUTH_INVALID_EVENT))
+      return Promise.reject(new Error(message || '登录失效,请重新登录'))
+    }
     if (code !== 200) {
       return Promise.reject(new Error(message || '请求失败'))
     }

+ 12 - 2
src/components/LoginModal.vue

@@ -120,9 +120,9 @@
 </template>
 
 <script setup lang="ts">
-import { ref, reactive } from 'vue'
+import { ref, reactive, watch } from 'vue'
 import { login } from '../api/auth'
-import { API_ENVIRONMENT_OPTIONS } from '../config'
+import { API_ENVIRONMENT_OPTIONS, type ApiEnvironment } from '../config'
 import { getApiEnvironment, setApiEnvironment, setToken } from '../utils/auth'
 
 interface Props {
@@ -132,6 +132,7 @@ interface Props {
 interface Emits {
   (e: 'success'): void
   (e: 'cancel'): void
+  (e: 'environment-change', environment: ApiEnvironment): void
 }
 
 defineProps<Props>()
@@ -148,6 +149,15 @@ const error = ref('')
 const showPassword = ref(false)
 const selectedEnvironment = ref(getApiEnvironment())
 
+watch(
+  selectedEnvironment,
+  (environment) => {
+    setApiEnvironment(environment)
+    emit('environment-change', environment)
+  },
+  { immediate: true }
+)
+
 const togglePasswordVisibility = () => {
   showPassword.value = !showPassword.value
 }

+ 1 - 0
src/utils/auth.ts

@@ -2,6 +2,7 @@ import { API_ENVIRONMENT_OPTIONS, DEFAULT_API_ENVIRONMENT, type ApiEnvironment }
 
 const TOKEN_KEY = 'auth_token'
 const API_ENVIRONMENT_KEY = 'api_environment'
+export const AUTH_INVALID_EVENT = 'auth-invalid'
 
 const isValidApiEnvironment = (value: string | null): value is ApiEnvironment => {
   if (!value) {