feat(electron-vue-template):重构认证与设备管理模块
- 统一token存取逻辑,封装getToken/setToken/removeToken方法 -优化设备ID获取逻辑,调整API路径 - 完善设备管理接口类型定义,增强类型安全 - 调整SSE连接逻辑,使用统一配置管理- 重构HTTP客户端,集中管理后端服务配置 - 更新认证相关API接口,完善请求/响应类型 - 优化设备列表展示逻辑,移除冗余字段 - 调整图片代理路径,统一API前缀 - 完善用户反馈列表展示功能,增强交互体验 - 移除冗余的错误处理逻辑,简化代码结构
This commit is contained in:
@@ -3,9 +3,11 @@ import {onMounted, ref, computed, defineAsyncComponent, type Component, onUnmoun
|
||||
import {ElMessage, ElMessageBox} from 'element-plus'
|
||||
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
||||
import 'element-plus/dist/index.css'
|
||||
import {authApi, TOKEN_KEY} from './api/auth'
|
||||
import {authApi} from './api/auth'
|
||||
import {deviceApi, type DeviceItem, type DeviceQuota} from './api/device'
|
||||
import {getOrCreateDeviceId} from './utils/deviceId'
|
||||
import {getToken, setToken, removeToken, getUsernameFromToken, getClientIdFromToken} from './utils/token'
|
||||
import {CONFIG} from './api/http'
|
||||
const LoginDialog = defineAsyncComponent(() => import('./components/auth/LoginDialog.vue'))
|
||||
const RegisterDialog = defineAsyncComponent(() => import('./components/auth/RegisterDialog.vue'))
|
||||
const NavigationBar = defineAsyncComponent(() => import('./components/layout/NavigationBar.vue'))
|
||||
@@ -147,7 +149,7 @@ function handleMenuSelect(key: string) {
|
||||
|
||||
async function handleLoginSuccess(data: { token: string; permissions?: string; expireTime?: string }) {
|
||||
try {
|
||||
localStorage.setItem(TOKEN_KEY, data.token)
|
||||
setToken(data.token)
|
||||
isAuthenticated.value = true
|
||||
showAuthDialog.value = false
|
||||
showRegDialog.value = false
|
||||
@@ -166,13 +168,13 @@ async function handleLoginSuccess(data: { token: string; permissions?: string; e
|
||||
} catch (e: any) {
|
||||
isAuthenticated.value = false
|
||||
showAuthDialog.value = true
|
||||
localStorage.removeItem(TOKEN_KEY)
|
||||
removeToken()
|
||||
ElMessage.error(e?.message || '设备注册失败')
|
||||
}
|
||||
}
|
||||
|
||||
function clearLocalAuth() {
|
||||
localStorage.removeItem(TOKEN_KEY)
|
||||
removeToken()
|
||||
isAuthenticated.value = false
|
||||
currentUsername.value = ''
|
||||
userPermissions.value = ''
|
||||
@@ -221,7 +223,7 @@ function backToLogin() {
|
||||
|
||||
async function checkAuth() {
|
||||
try {
|
||||
const token = localStorage.getItem(TOKEN_KEY)
|
||||
const token = getToken()
|
||||
if (!token) {
|
||||
if (['rakuten', 'amazon', 'zebra', 'shopee'].includes(activeMenu.value)) {
|
||||
showAuthDialog.value = true
|
||||
@@ -229,40 +231,24 @@ async function checkAuth() {
|
||||
return
|
||||
}
|
||||
|
||||
const res: any = await authApi.verifyToken(token)
|
||||
const res = await authApi.verifyToken(token)
|
||||
isAuthenticated.value = true
|
||||
currentUsername.value = getUsernameFromToken(token) || ''
|
||||
userPermissions.value = res?.data?.permissions || res?.permissions || ''
|
||||
currentUsername.value = getUsernameFromToken(token)
|
||||
userPermissions.value = res.data.permissions || ''
|
||||
|
||||
const expireTime = res?.data?.expireTime || res?.expireTime
|
||||
if (expireTime) vipExpireTime.value = new Date(expireTime)
|
||||
if (res.data.expireTime) {
|
||||
vipExpireTime.value = new Date(res.data.expireTime)
|
||||
}
|
||||
|
||||
SSEManager.connect()
|
||||
} catch {
|
||||
localStorage.removeItem(TOKEN_KEY)
|
||||
removeToken()
|
||||
if (['rakuten', 'amazon', 'zebra', 'shopee'].includes(activeMenu.value)) {
|
||||
showAuthDialog.value = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getClientIdFromToken(token?: string) {
|
||||
try {
|
||||
const t = token || localStorage.getItem(TOKEN_KEY)
|
||||
if (!t) return ''
|
||||
return JSON.parse(atob(t.split('.')[1])).clientId || ''
|
||||
} catch {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
function getUsernameFromToken(token: string) {
|
||||
try {
|
||||
return JSON.parse(atob(token.split('.')[1])).username || ''
|
||||
} catch {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
const SSEManager = {
|
||||
connection: null as EventSource | null,
|
||||
@@ -270,19 +256,13 @@ const SSEManager = {
|
||||
if (this.connection) return
|
||||
|
||||
try {
|
||||
const token = localStorage.getItem(TOKEN_KEY)
|
||||
if (!token) return console.warn('SSE连接失败: 没有token')
|
||||
const token = getToken()
|
||||
if (!token) return
|
||||
|
||||
const clientId = getClientIdFromToken(token)
|
||||
if (!clientId) return console.warn('SSE连接失败: 无法获取clientId')
|
||||
const clientId = getClientIdFromToken()
|
||||
if (!clientId) return
|
||||
|
||||
let sseUrl = 'http://192.168.1.89:8085/monitor/account/events'
|
||||
try {
|
||||
const resp = await fetch('/api/config/server')
|
||||
if (resp.ok) sseUrl = (await resp.json()).sseUrl || sseUrl
|
||||
} catch {}
|
||||
|
||||
const src = new EventSource(`${sseUrl}?clientId=${clientId}&token=${token}`)
|
||||
const src = new EventSource(`${CONFIG.SSE_URL}?clientId=${clientId}&token=${token}`)
|
||||
this.connection = src
|
||||
src.onopen = () => console.log('SSE连接已建立')
|
||||
src.onmessage = (e) => this.handleMessage(e)
|
||||
@@ -335,10 +315,10 @@ const SSEManager = {
|
||||
|
||||
disconnect() {
|
||||
if (this.connection) {
|
||||
try { this.connection.close() } catch {}
|
||||
this.connection.close()
|
||||
this.connection = null
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async function openDeviceManager() {
|
||||
@@ -363,13 +343,12 @@ async function fetchDeviceData() {
|
||||
deviceLoading.value = true
|
||||
const [quotaRes, listRes] = await Promise.all([
|
||||
deviceApi.getQuota(currentUsername.value),
|
||||
deviceApi.list(currentUsername.value),
|
||||
]) as any[]
|
||||
deviceApi.list(currentUsername.value)
|
||||
])
|
||||
|
||||
deviceQuota.value = quotaRes?.data || quotaRes || {limit: 0, used: 0}
|
||||
const clientId = await getClientIdFromToken()
|
||||
const list = listRes?.data || listRes || []
|
||||
devices.value = list.map(d => ({...d, isCurrent: d.deviceId === clientId}))
|
||||
deviceQuota.value = quotaRes.data
|
||||
const clientId = getClientIdFromToken()
|
||||
devices.value = listRes.data.map(d => ({...d, isCurrent: d.deviceId === clientId}))
|
||||
} catch (e: any) {
|
||||
ElMessage.error(e?.message || '获取设备列表失败')
|
||||
} finally {
|
||||
@@ -377,7 +356,7 @@ async function fetchDeviceData() {
|
||||
}
|
||||
}
|
||||
|
||||
async function confirmRemoveDevice(row: DeviceItem & { isCurrent?: boolean }) {
|
||||
async function confirmRemoveDevice(row: DeviceItem) {
|
||||
try {
|
||||
await ElMessageBox.confirm('确定要移除该设备吗?', '你确定要移除设备吗?', {
|
||||
confirmButtonText: '确定移除',
|
||||
@@ -387,7 +366,7 @@ async function confirmRemoveDevice(row: DeviceItem & { isCurrent?: boolean }) {
|
||||
|
||||
await deviceApi.remove({deviceId: row.deviceId})
|
||||
devices.value = devices.value.filter(d => d.deviceId !== row.deviceId)
|
||||
deviceQuota.value.used = Math.max(0, (deviceQuota.value.used || 0) - 1)
|
||||
deviceQuota.value.used = Math.max(0, deviceQuota.value.used - 1)
|
||||
|
||||
if (row.deviceId === getClientIdFromToken()) {
|
||||
clearLocalAuth()
|
||||
|
||||
Reference in New Issue
Block a user