import { defineStore } from 'pinia' import { computed, ref } from 'vue' import { AUTH_API, TOKEN_KEY, REFRESH_TOKEN_KEY, USER_INFO_KEY, PAGE_PATHS } from '@/config/api' import { request, parseResponseJson } from '@/utils/request' import { buildMiniEncryptedLoginBody } from '@/utils/loginRsa' export const useUserStore = defineStore('user', () => { const token = ref('') const refreshToken = ref('') const userInfo = ref(null) const isLoading = ref(false) const menuAll = ref(false) const menuCodes = ref([]) function normalizeUserInfo(raw) { if (!raw || typeof raw !== 'object') return raw || null const avatarUrl = raw.avatarUrl != null && String(raw.avatarUrl).trim() ? String(raw.avatarUrl).trim() : raw.avatar_url != null && String(raw.avatar_url).trim() ? String(raw.avatar_url).trim() : '' return { ...raw, avatarUrl } } const isLoggedIn = computed(() => !!token.value && !!userInfo.value) const userRole = computed(() => userInfo.value?.role || '') /** 登录成功默认进入工作台 Tab */ const homePath = computed(() => PAGE_PATHS.workbench) function checkLoginStatus() { const savedToken = uni.getStorageSync(TOKEN_KEY) const savedUserInfo = uni.getStorageSync(USER_INFO_KEY) const savedRefreshToken = uni.getStorageSync(REFRESH_TOKEN_KEY) const normalizedToken = typeof savedToken === 'string' ? savedToken.trim() : savedToken ? String(savedToken).trim() : '' let normalizedUserInfo = null if (typeof savedUserInfo === 'string') { try { normalizedUserInfo = normalizeUserInfo(JSON.parse(savedUserInfo)) } catch (error) { normalizedUserInfo = null } } else if (savedUserInfo && typeof savedUserInfo === 'object') { normalizedUserInfo = normalizeUserInfo(savedUserInfo) } if (normalizedToken && normalizedUserInfo) { token.value = normalizedToken refreshToken.value = typeof savedRefreshToken === 'string' ? savedRefreshToken : '' userInfo.value = normalizedUserInfo return } token.value = '' refreshToken.value = '' userInfo.value = null } function setLoginInfo(data) { token.value = data.token || '' refreshToken.value = data.refreshToken || '' userInfo.value = normalizeUserInfo(data.userInfo || null) uni.setStorageSync(TOKEN_KEY, token.value) uni.setStorageSync(REFRESH_TOKEN_KEY, refreshToken.value) uni.setStorageSync(USER_INFO_KEY, userInfo.value) } async function fetchMenuCodes() { if (!token.value || !String(token.value).trim()) { menuAll.value = false menuCodes.value = [] return } try { const res = await request({ url: AUTH_API.MENU_CODES, method: 'GET' }) const result = parseResponseJson(res) if (!result || result.code !== 200 || !result.data) { menuAll.value = false menuCodes.value = [] return } const data = result.data menuAll.value = !!(data.all || data.isSuperAdmin) menuCodes.value = Array.isArray(data.menuCodes) ? data.menuCodes.map((c) => String(c || '').trim()).filter(Boolean) : [] } catch { menuAll.value = false menuCodes.value = [] } } async function login(params) { isLoading.value = true try { const encryptedBody = await buildMiniEncryptedLoginBody(params.username, params.password) const res = await request({ url: AUTH_API.LOGIN, method: 'POST', data: encryptedBody }) const result = parseResponseJson(res) if (result && result.code === 200 && result.data) { setLoginInfo({ token: result.data.token, refreshToken: result.data.refreshToken, userInfo: result.data.userInfo }) await fetchMenuCodes() return true } uni.showToast({ title: (result && result.message) || '登录失败', icon: 'none' }) return false } catch (error) { uni.showToast({ title: (error && error.message) || '网络请求失败', icon: 'none' }) return false } finally { isLoading.value = false } } function clearLoginInfo() { token.value = '' refreshToken.value = '' userInfo.value = null uni.removeStorageSync(TOKEN_KEY) uni.removeStorageSync(REFRESH_TOKEN_KEY) uni.removeStorageSync(USER_INFO_KEY) menuAll.value = false menuCodes.value = [] } async function logout() { try { await request({ url: AUTH_API.LOGOUT, method: 'POST' }) } catch (error) { // ignore } finally { clearLoginInfo() uni.reLaunch({ url: PAGE_PATHS.login }) } } function navigateToHome() { uni.reLaunch({ url: homePath.value }) } function updateUserInfo(info) { if (!userInfo.value || !info) return userInfo.value = normalizeUserInfo({ ...userInfo.value, ...info }) uni.setStorageSync(USER_INFO_KEY, userInfo.value) } async function refreshUserInfo() { if (!token.value || !String(token.value).trim()) return try { const res = await request({ url: AUTH_API.CURRENT_USER, method: 'GET' }) const result = parseResponseJson(res) if (result.code !== 200 || !result.data) return userInfo.value = normalizeUserInfo(result.data) uni.setStorageSync(USER_INFO_KEY, userInfo.value) } catch { // ignore } } return { token, refreshToken, userInfo, isLoading, menuAll, menuCodes, isLoggedIn, userRole, homePath, checkLoginStatus, login, logout, clearLoginInfo, navigateToHome, updateUserInfo, refreshUserInfo, fetchMenuCodes } })