mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-23 00:53:33 +00:00
- 更新 AccountForm.vue 中的占位符文本为 i18n 语言包中的键 - 修改 ConfirmModal.vue 中的确认和取消按钮文本为 i18n 语言包中的键 - 更新 CustomDropdown.vue 中的占位符文本为 i18n 语言包中的键 - 修改 app.js 中的应用标题为英文版本 - 更新 router/index.js 中的日志输出为英文 - 在 accounts.js 和 apiKeys.js 中的错误处理信息中引入 i18n 键以提升多语言一致性 - 更新 dashboard.js 中的系统状态和错误日志为 i18n 键 - 在 DashboardView.vue 中的多个文本替换为 i18n 语言包中的键
138 lines
3.6 KiB
JavaScript
138 lines
3.6 KiB
JavaScript
import { defineStore } from 'pinia'
|
|
import { ref, computed } from 'vue'
|
|
import router from '@/router'
|
|
import i18n from '@/i18n'
|
|
import { apiClient } from '@/config/api'
|
|
|
|
export const useAuthStore = defineStore('auth', () => {
|
|
// 状态
|
|
const isLoggedIn = ref(false)
|
|
const authToken = ref(localStorage.getItem('authToken') || '')
|
|
const username = ref('')
|
|
const loginError = ref('')
|
|
const loginLoading = ref(false)
|
|
const oemSettings = ref({
|
|
siteName: 'Claude Relay Service',
|
|
siteIcon: '',
|
|
siteIconData: '',
|
|
faviconData: ''
|
|
})
|
|
const oemLoading = ref(true)
|
|
|
|
// 计算属性
|
|
const isAuthenticated = computed(() => !!authToken.value && isLoggedIn.value)
|
|
const token = computed(() => authToken.value)
|
|
const user = computed(() => ({ username: username.value }))
|
|
|
|
// 方法
|
|
async function login(credentials) {
|
|
loginLoading.value = true
|
|
loginError.value = ''
|
|
|
|
try {
|
|
const result = await apiClient.post('/web/auth/login', credentials)
|
|
|
|
if (result.success) {
|
|
authToken.value = result.token
|
|
username.value = result.username || credentials.username
|
|
isLoggedIn.value = true
|
|
localStorage.setItem('authToken', result.token)
|
|
|
|
await router.push('/dashboard')
|
|
} else {
|
|
loginError.value = result.message || i18n.global.t('login.loginFailed')
|
|
}
|
|
} catch (error) {
|
|
loginError.value = error.message || i18n.global.t('login.loginFailedCheck')
|
|
} finally {
|
|
loginLoading.value = false
|
|
}
|
|
}
|
|
|
|
function logout() {
|
|
isLoggedIn.value = false
|
|
authToken.value = ''
|
|
username.value = ''
|
|
localStorage.removeItem('authToken')
|
|
router.push('/login')
|
|
}
|
|
|
|
function checkAuth() {
|
|
if (authToken.value) {
|
|
isLoggedIn.value = true
|
|
// 验证token有效性
|
|
verifyToken()
|
|
}
|
|
}
|
|
|
|
async function verifyToken() {
|
|
try {
|
|
// 获取当前用户信息
|
|
const userResult = await apiClient.get('/web/auth/user')
|
|
if (userResult.success && userResult.user) {
|
|
username.value = userResult.user.username
|
|
}
|
|
|
|
// 使用 dashboard 端点来验证 token
|
|
// 如果 token 无效,会抛出错误
|
|
const result = await apiClient.get('/admin/dashboard')
|
|
if (!result.success) {
|
|
logout()
|
|
}
|
|
} catch (error) {
|
|
// token 无效,需要重新登录
|
|
logout()
|
|
}
|
|
}
|
|
|
|
async function loadOemSettings() {
|
|
oemLoading.value = true
|
|
try {
|
|
const result = await apiClient.get('/admin/oem-settings')
|
|
if (result.success && result.data) {
|
|
oemSettings.value = { ...oemSettings.value, ...result.data }
|
|
|
|
// 设置favicon
|
|
if (result.data.siteIconData || result.data.siteIcon) {
|
|
const link = document.querySelector("link[rel*='icon']") || document.createElement('link')
|
|
link.type = 'image/x-icon'
|
|
link.rel = 'shortcut icon'
|
|
link.href = result.data.siteIconData || result.data.siteIcon
|
|
document.getElementsByTagName('head')[0].appendChild(link)
|
|
}
|
|
|
|
// 设置页面标题
|
|
if (result.data.siteName) {
|
|
document.title = `${result.data.siteName} - ${i18n.global.t('header.adminPanel')}`
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error(i18n.global.t('common.errors.loadOemSettingsFailed'), error)
|
|
} finally {
|
|
oemLoading.value = false
|
|
}
|
|
}
|
|
|
|
return {
|
|
// 状态
|
|
isLoggedIn,
|
|
authToken,
|
|
username,
|
|
loginError,
|
|
loginLoading,
|
|
oemSettings,
|
|
oemLoading,
|
|
|
|
// 计算属性
|
|
isAuthenticated,
|
|
token,
|
|
user,
|
|
|
|
// 方法
|
|
login,
|
|
logout,
|
|
checkAuth,
|
|
loadOemSettings
|
|
}
|
|
})
|