Files
one-pipe-system/src/composables/useLogin.ts
sexygoat 2b3119c549
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 4m51s
fix(operator): fix operator edit issue
2026-04-10 14:00:21 +08:00

261 lines
6.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 登录逻辑 Composable
*/
import { ref, reactive, computed, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { ElMessage, ElNotification } from 'element-plus'
import type { FormInstance, FormRules } from 'element-plus'
import { useUserStore } from '@/store/modules/user'
import { HOME_PAGE } from '@/router/routesAlias'
import AppConfig from '@/config'
import { AuthService } from '@/api/modules'
import { ApiStatus } from '@/utils/http/status'
import { MOCK_ACCOUNTS, mockLogin, mockGetUserInfo, type MockAccount } from '@/mock/auth'
import { saveCredentials, getRememberedCredentials } from '@/utils/auth/rememberPassword'
import { usernameRules, passwordRules } from '@/utils/auth/loginValidation'
import { getRedirectPath } from '@/router/guards/permission'
// 开发模式:是否使用 Mock 数据
const USE_MOCK = false
/**
* 登录表单数据
*/
interface LoginForm {
account: string
username: string
password: string
rememberPassword: boolean
}
export function useLogin() {
const { t } = useI18n()
const router = useRouter()
const route = useRoute()
const userStore = useUserStore()
// 表单引用
const formRef = ref<FormInstance>()
// 加载状态
const loading = ref(false)
// 表单数据
const formData = reactive<LoginForm>({
account: '',
username: '',
password: '',
rememberPassword: true
})
// 验证规则
const rules = computed<FormRules>(() => ({
username: usernameRules(t),
password: passwordRules(t)
}))
// Mock 账号列表
const mockAccounts = computed<MockAccount[]>(() => MOCK_ACCOUNTS)
/**
* 初始化表单
*/
const initForm = () => {
// 尝试加载记住的密码
const remembered = getRememberedCredentials()
if (remembered) {
formData.username = remembered.username
formData.password = remembered.password
formData.rememberPassword = remembered.rememberPassword
// 如果使用 Mock尝试匹配 Mock 账号
if (USE_MOCK) {
const matchedAccount = MOCK_ACCOUNTS.find((acc) => acc.username === remembered.username)
if (matchedAccount) {
formData.account = matchedAccount.key
}
}
} else {
// 开发环境:使用真实 API 默认账号
if (import.meta.env.MODE === 'development') {
formData.username = 'admin'
formData.password = 'Admin@123456'
formData.rememberPassword = false
}
// 生产环境:不填充默认值
}
}
/**
* 设置 Mock 账号
*/
const setupAccount = (key: string) => {
const selectedAccount = MOCK_ACCOUNTS.find((account) => account.key === key)
if (selectedAccount) {
formData.account = key
formData.username = selectedAccount.username
formData.password = selectedAccount.password
}
}
/**
* 执行登录
*/
const handleLogin = async () => {
if (!formRef.value) return
try {
// 验证表单
const valid = await formRef.value.validate()
if (!valid) return
loading.value = true
// 判断使用 Mock 还是真实 API
if (USE_MOCK) {
await handleMockLogin()
} else {
await handleRealLogin()
}
} catch (error: any) {
console.error('登录失败:', error)
} finally {
loading.value = false
}
}
/**
* Mock 登录(开发测试用)
*/
const handleMockLogin = async () => {
const loginResult = mockLogin(formData.username, formData.password)
if (!loginResult) {
console.log(t('login.error.invalidCredentials'))
return
}
// 保存 Token
userStore.setToken(loginResult.access_token, loginResult.refresh_token)
// 获取用户信息
const userInfo = mockGetUserInfo(loginResult.access_token)
if (!userInfo) {
console.log(t('login.error.getUserInfoFailed'))
return
}
// 保存用户信息
userStore.setUserInfo(userInfo)
userStore.setLoginStatus(true)
// 保存记住密码
saveCredentials(formData.username, formData.password, formData.rememberPassword)
// 显示登录成功提示
showLoginSuccessNotice()
// 跳转到重定向页面或首页
const redirectPath = getRedirectPath(route)
await router.push(redirectPath || HOME_PAGE)
}
/**
* 真实 API 登录
*/
const handleRealLogin = async () => {
// 调用登录接口
const response = await AuthService.login({
username: formData.username,
password: formData.password
})
// 检查响应状态
if (response.code !== ApiStatus.success) {
console.log(response.msg || t('login.error.invalidCredentials'))
return
}
// 检查返回数据
if (!response.data || !response.data.access_token) {
console.log(t('login.error.loginFailed'))
return
}
// 检查用户类型 - 禁止企业账号登录
if (response.data.user && response.data.user.user_type === 4) {
console.log('企业账号无法登录后台管理系统')
return
}
// 保存 Token
userStore.setToken(response.data.access_token, response.data.refresh_token)
// 保存用户信息
if (response.data.user) {
userStore.setUserInfo(response.data.user)
userStore.setLoginStatus(true)
} else {
console.log(t('login.error.getUserInfoFailed'))
return
}
// 保存权限、菜单和按钮
if (response.data.permissions) {
userStore.setPermissions(response.data.permissions)
}
if (response.data.menus) {
userStore.setMenus(response.data.menus)
}
if (response.data.buttons) {
userStore.setButtons(response.data.buttons)
}
// 保存记住密码
saveCredentials(formData.username, formData.password, formData.rememberPassword)
// 显示登录成功提示
showLoginSuccessNotice()
// 等待数据持久化完成
await new Promise((resolve) => setTimeout(resolve, 100))
// 跳转到重定向页面或首页
const redirectPath = getRedirectPath(route)
await router.push(redirectPath || HOME_PAGE)
}
/**
* 显示登录成功通知
*/
const showLoginSuccessNotice = () => {
setTimeout(() => {
ElNotification({
title: t('login.success.title'),
type: 'success',
duration: 2500,
zIndex: 10000,
message: `${t('login.success.message')}, ${AppConfig.systemInfo.name}!`
})
}, 150)
}
// 组件挂载时初始化
onMounted(() => {
initForm()
})
return {
formRef,
formData,
rules,
loading,
mockAccounts,
setupAccount,
handleLogin
}
}