feat: 接入真实平台登录态
- login/session: 对接后端登录、鉴权恢复和首次改密 - api/store: 恢复 BPMN XML 真实接口并携带 Bearer token - layout/settings: 展示真实角色、审计 JSON 和通知平台配置文档
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* 平台 Pinia store 聚合后端项目、发布、设置和审计数据。
|
||||
*/
|
||||
import { computed, ref } from 'vue'
|
||||
import { defineStore } from 'pinia'
|
||||
import { devopsApi } from '../services/devopsApi'
|
||||
|
||||
+151
-8
@@ -1,28 +1,171 @@
|
||||
/**
|
||||
* 维护后端真实登录态,前端只保存 DevOps API token,不保存任何第三方密钥。
|
||||
*/
|
||||
import { computed, ref } from 'vue'
|
||||
import { defineStore } from 'pinia'
|
||||
import { devopsApi } from '../services/devopsApi'
|
||||
import { setAuthToken } from '../services/http'
|
||||
import type {
|
||||
AuthenticatedUser,
|
||||
ChangePasswordPayload,
|
||||
LoginPayload,
|
||||
} from '../types/devops'
|
||||
|
||||
const STORAGE_KEY = 'devops-platform-session'
|
||||
|
||||
type StoredSession = {
|
||||
token: string
|
||||
expiresAt: string
|
||||
user: AuthenticatedUser
|
||||
}
|
||||
|
||||
export const useSessionStore = defineStore('session', () => {
|
||||
const operator = ref('ops-admin')
|
||||
const role = ref<'admin' | 'operator' | 'viewer'>('admin')
|
||||
const token = ref('local-session')
|
||||
const restored = loadStoredSession()
|
||||
const operator = ref(restored?.user.account ?? '')
|
||||
const displayName = ref(restored?.user.displayName ?? '')
|
||||
const role = ref<AuthenticatedUser['role'] | ''>(restored?.user.role ?? '')
|
||||
const token = ref(restored?.token ?? '')
|
||||
const expiresAt = ref(restored?.expiresAt ?? '')
|
||||
const currentUser = ref<AuthenticatedUser | null>(restored?.user ?? null)
|
||||
const bootstrapped = ref(false)
|
||||
|
||||
const isAuthenticated = computed(() => Boolean(token.value))
|
||||
setAuthToken(token.value)
|
||||
|
||||
function login(name: string) {
|
||||
operator.value = name || 'ops-admin'
|
||||
token.value = 'local-session'
|
||||
const isAuthenticated = computed(() => Boolean(token.value && currentUser.value))
|
||||
const mustChangePassword = computed(() =>
|
||||
Boolean(currentUser.value?.mustChangePassword),
|
||||
)
|
||||
const roleLabel = computed(() => {
|
||||
if (role.value === 'super_admin') {
|
||||
return '超级管理员'
|
||||
}
|
||||
|
||||
if (role.value === 'member') {
|
||||
return '普通成员'
|
||||
}
|
||||
|
||||
return '未登录'
|
||||
})
|
||||
|
||||
async function bootstrap(): Promise<boolean> {
|
||||
if (bootstrapped.value) {
|
||||
return isAuthenticated.value
|
||||
}
|
||||
|
||||
bootstrapped.value = true
|
||||
|
||||
if (!token.value) {
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
const user = await devopsApi.getCurrentUser()
|
||||
applyUser(user)
|
||||
persist()
|
||||
return true
|
||||
} catch {
|
||||
clearSession()
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function logout() {
|
||||
async function login(payload: LoginPayload) {
|
||||
const result = await devopsApi.login(payload)
|
||||
token.value = result.token
|
||||
expiresAt.value = result.expiresAt
|
||||
setAuthToken(result.token)
|
||||
applyUser(result.user)
|
||||
persist()
|
||||
bootstrapped.value = true
|
||||
return result.user
|
||||
}
|
||||
|
||||
async function changePassword(payload: ChangePasswordPayload) {
|
||||
const user = await devopsApi.changePassword(payload)
|
||||
applyUser(user)
|
||||
persist()
|
||||
return user
|
||||
}
|
||||
|
||||
async function logout() {
|
||||
if (token.value) {
|
||||
try {
|
||||
await devopsApi.logout()
|
||||
} catch {
|
||||
// 退出以清理本地登录态为准,后端当前无状态 token 无需强依赖 logout 成功。
|
||||
}
|
||||
}
|
||||
|
||||
clearSession()
|
||||
}
|
||||
|
||||
function applyUser(user: AuthenticatedUser) {
|
||||
currentUser.value = user
|
||||
operator.value = user.account
|
||||
displayName.value = user.displayName
|
||||
role.value = user.role
|
||||
}
|
||||
|
||||
function persist() {
|
||||
if (!token.value || !currentUser.value) {
|
||||
localStorage.removeItem(STORAGE_KEY)
|
||||
return
|
||||
}
|
||||
|
||||
const stored: StoredSession = {
|
||||
token: token.value,
|
||||
expiresAt: expiresAt.value,
|
||||
user: currentUser.value,
|
||||
}
|
||||
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(stored))
|
||||
}
|
||||
|
||||
function clearSession() {
|
||||
operator.value = ''
|
||||
displayName.value = ''
|
||||
role.value = ''
|
||||
token.value = ''
|
||||
expiresAt.value = ''
|
||||
currentUser.value = null
|
||||
setAuthToken()
|
||||
localStorage.removeItem(STORAGE_KEY)
|
||||
}
|
||||
|
||||
return {
|
||||
operator,
|
||||
displayName,
|
||||
role,
|
||||
roleLabel,
|
||||
token,
|
||||
expiresAt,
|
||||
currentUser,
|
||||
isAuthenticated,
|
||||
mustChangePassword,
|
||||
bootstrap,
|
||||
login,
|
||||
changePassword,
|
||||
logout,
|
||||
}
|
||||
})
|
||||
|
||||
function loadStoredSession(): StoredSession | null {
|
||||
try {
|
||||
const rawValue = localStorage.getItem(STORAGE_KEY)
|
||||
|
||||
if (!rawValue) {
|
||||
return null
|
||||
}
|
||||
|
||||
const parsed = JSON.parse(rawValue) as StoredSession
|
||||
|
||||
if (!parsed.token || !parsed.user?.account) {
|
||||
return null
|
||||
}
|
||||
|
||||
return parsed
|
||||
} catch {
|
||||
localStorage.removeItem(STORAGE_KEY)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user