Files
chongming-web/src/composables/useAdminAuth.ts
T

75 lines
2.5 KiB
TypeScript
Raw Normal View History

/**
* 管理端登录状态(跨页面共享单例)。
*
* 参数配置页与 Worker 管理页共用同一份 token(localStorage 的 cm_admin_token),
* 在任一页面登录后另一页面无需重复登录。抽成模块级单例而非 Pinia store,
* 避免为这点状态引入额外样板。
*/
import { computed, ref } from 'vue'
import { ElMessage } from 'element-plus'
import { login, parseJwt, TOKEN_KEY, type AuthUser } from '@/api/workerAdmin'
const token = ref(localStorage.getItem(TOKEN_KEY) || '')
const currentUser = ref<AuthUser | null>(null)
const username = ref('')
const password = ref('')
const logging = ref(false)
/** 从持久化 token 恢复身份(进入页面时调用;权限校验仍以后端为准) */
export function restoreAuth(): AuthUser | null {
const t = token.value.trim()
currentUser.value = t ? parseJwt(t) : null
return currentUser.value
}
export function useAdminAuth() {
const isLoggedIn = computed(() => !!token.value.trim())
/**
* 登录并领取管理 Token。
* @returns 登录成功时的用户信息;失败返回 null(已弹出提示)。
*/
const doLogin = async (): Promise<AuthUser | null> => {
const name = username.value.trim()
if (!name || !password.value) {
ElMessage.warning('请输入用户名和密码')
return null
}
logging.value = true
try {
const data = await login(name, password.value)
// 后端登录失败仍返回 HTTP 200,仅 result=fail + 空 token
if (data.result !== 'success' || !data.token) {
ElMessage.error(`登录失败:${data.message || '用户名或密码错误'}`)
return null
}
token.value = data.token
localStorage.setItem(TOKEN_KEY, data.token)
username.value = ''
password.value = ''
const info = parseJwt(data.token)
currentUser.value = info
ElMessage.success(`登录成功:${(info?.username || '').trim() || '未知用户'}`)
if (!info?.is_superuser) {
ElMessage.error('权限不足:仅超级管理员可管理配置,操作将被拒绝')
return null
}
return info
} catch (e: any) {
ElMessage.error(`登录失败:${e.message}`)
return null
} finally {
logging.value = false
}
}
const logout = () => {
localStorage.removeItem(TOKEN_KEY)
token.value = ''
currentUser.value = null
ElMessage.success('已退出登录')
}
return { token, currentUser, username, password, logging, isLoggedIn, doLogin, logout }
}