chore: initial baseline with P0-safety .gitignore

This commit is contained in:
Simon
2026-06-14 16:49:18 +08:00
commit 63262292d7
510 changed files with 146008 additions and 0 deletions
+174
View File
@@ -0,0 +1,174 @@
// =============================================================================
// IT智能服务台 — Portal 状态管理
// =============================================================================
// 说明:Portal 统一入口的状态管理,负责:
// 1. 用户信息和角色管理
// 2. Token 管理
// 3. 角色切换
// =============================================================================
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { getUserRoles, switchRole as apiSwitchRole, type UserInfo, type Role } from '@/api/portal'
/**
* Portal 状态管理 Store
*/
export const usePortalStore = defineStore('portal', () => {
// ==================== 状态 ====================
// 用户信息
const userInfo = ref<UserInfo | null>(null)
// 加载状态
const loading = ref(false)
// 错误信息
const error = ref<string | null>(null)
// ==================== 计算属性 ====================
// Token
const token = computed(() => localStorage.getItem('portal_token'))
// 是否已认证
const isAuthenticated = computed(() => !!token.value)
// 用户角色列表
const roles = computed(() => userInfo.value?.roles || [])
// 当前选择的角色
const currentRole = computed(() => userInfo.value?.current_role || 'user')
// 是否有坐席角色
const hasAgentRole = computed(() => roles.value.some((r: Role) => r.name === 'agent'))
// 是否有管理员角色
const hasAdminRole = computed(() => roles.value.some((r: Role) => r.name === 'admin'))
// 角色数量(用于决定是否显示选择页)
const roleCount = computed(() => roles.value.length)
// ==================== 方法 ====================
/**
* 设置 Token
* @param newToken Token 字符串
*/
function setToken(newToken: string) {
localStorage.setItem('portal_token', newToken)
}
/**
* 清除认证信息
*/
function clearAuth() {
localStorage.removeItem('portal_token')
localStorage.removeItem('portal_user')
userInfo.value = null
}
/**
* 获取用户角色信息
* 从后端 API 获取当前用户的角色列表
*/
async function fetchUserInfo() {
if (!token.value) {
error.value = '未登录'
return
}
loading.value = true
error.value = null
try {
const data = await getUserRoles()
userInfo.value = data
// 缓存到 localStorage
localStorage.setItem('portal_user', JSON.stringify(data))
} catch (err: any) {
console.error('获取用户信息失败:', err)
error.value = err.response?.data?.detail || '获取用户信息失败'
// 如果是 401 错误,清除认证信息
if (err.response?.status === 401) {
clearAuth()
}
} finally {
loading.value = false
}
}
/**
* 切换角色
* @param newRole 目标角色标识
*/
async function switchToRole(newRole: string) {
if (!token.value) {
error.value = '未登录'
return
}
loading.value = true
error.value = null
try {
const result = await apiSwitchRole(newRole)
// 更新本地状态
if (userInfo.value) {
userInfo.value.current_role = result.current_role
}
// 跳转到目标页面
window.location.href = result.redirect_url
} catch (err: any) {
console.error('角色切换失败:', err)
error.value = err.response?.data?.detail || '角色切换失败'
} finally {
loading.value = false
}
}
/**
* 从缓存恢复用户信息
* 用于页面刷新时恢复状态
*/
function restoreFromCache() {
const cachedUser = localStorage.getItem('portal_user')
if (cachedUser) {
try {
userInfo.value = JSON.parse(cachedUser)
} catch (e) {
console.error('解析缓存用户信息失败:', e)
localStorage.removeItem('portal_user')
}
}
}
// ==================== 返回 ====================
return {
// 状态
userInfo,
loading,
error,
// 计算属性
token,
isAuthenticated,
roles,
currentRole,
hasAgentRole,
hasAdminRole,
roleCount,
// 方法
setToken,
clearAuth,
fetchUserInfo,
switchToRole,
restoreFromCache,
}
})