feat(electron-vue-template):重构认证与设备管理模块

- 统一token存取逻辑,封装getToken/setToken/removeToken方法
-优化设备ID获取逻辑,调整API路径
- 完善设备管理接口类型定义,增强类型安全
- 调整SSE连接逻辑,使用统一配置管理- 重构HTTP客户端,集中管理后端服务配置
- 更新认证相关API接口,完善请求/响应类型
- 优化设备列表展示逻辑,移除冗余字段
- 调整图片代理路径,统一API前缀
- 完善用户反馈列表展示功能,增强交互体验
- 移除冗余的错误处理逻辑,简化代码结构
This commit is contained in:
2025-10-16 10:37:00 +08:00
parent 6f04658265
commit 132299c4b7
37 changed files with 2193 additions and 682 deletions

View File

@@ -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()