Initial commit: One Pipe System
完整的管理系统,包含账户管理、卡片管理、套餐管理、财务管理等功能模块。 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
273
src/composables/useLogin.ts
Normal file
273
src/composables/useLogin.ts
Normal file
@@ -0,0 +1,273 @@
|
||||
/**
|
||||
* 登录逻辑 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/authApi'
|
||||
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 isPassing = ref(false)
|
||||
const isClickPass = 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
|
||||
|
||||
// 检查拖拽验证
|
||||
if (!isPassing.value) {
|
||||
isClickPass.value = true
|
||||
ElMessage.warning(t('login.placeholder[2]'))
|
||||
return
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
|
||||
// 判断使用 Mock 还是真实 API
|
||||
if (USE_MOCK) {
|
||||
await handleMockLogin()
|
||||
} else {
|
||||
await handleRealLogin()
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('登录失败:', error)
|
||||
ElMessage.error(error.message || t('login.error.loginFailed'))
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock 登录(开发测试用)
|
||||
*/
|
||||
const handleMockLogin = async () => {
|
||||
const loginResult = mockLogin(formData.username, formData.password)
|
||||
|
||||
if (!loginResult) {
|
||||
ElMessage.error(t('login.error.invalidCredentials'))
|
||||
return
|
||||
}
|
||||
|
||||
// 保存 Token
|
||||
userStore.setToken(loginResult.token, loginResult.refreshToken)
|
||||
|
||||
// 获取用户信息
|
||||
const userInfo = mockGetUserInfo(loginResult.token)
|
||||
|
||||
if (!userInfo) {
|
||||
ElMessage.error(t('login.error.getUserInfoFailed'))
|
||||
return
|
||||
}
|
||||
|
||||
// 保存用户信息
|
||||
userStore.setUserInfo(userInfo)
|
||||
userStore.setLoginStatus(true)
|
||||
|
||||
// 保存记住密码
|
||||
saveCredentials(formData.username, formData.password, formData.rememberPassword)
|
||||
|
||||
// 显示登录成功提示
|
||||
showLoginSuccessNotice()
|
||||
|
||||
// 跳转到重定向页面或首页
|
||||
const redirectPath = getRedirectPath(route)
|
||||
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) {
|
||||
ElMessage.error(response.msg || t('login.error.invalidCredentials'))
|
||||
return
|
||||
}
|
||||
|
||||
// 检查返回数据
|
||||
if (!response.data || !response.data.access_token) {
|
||||
ElMessage.error(t('login.error.loginFailed'))
|
||||
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 {
|
||||
ElMessage.error(t('login.error.getUserInfoFailed'))
|
||||
return
|
||||
}
|
||||
|
||||
// 保存记住密码
|
||||
saveCredentials(formData.username, formData.password, formData.rememberPassword)
|
||||
|
||||
// 显示登录成功提示
|
||||
showLoginSuccessNotice()
|
||||
|
||||
// 跳转到重定向页面或首页
|
||||
const redirectPath = getRedirectPath(route)
|
||||
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)
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置拖拽验证
|
||||
*/
|
||||
const resetDragVerify = () => {
|
||||
isPassing.value = false
|
||||
isClickPass.value = false
|
||||
}
|
||||
|
||||
// 组件挂载时初始化
|
||||
onMounted(() => {
|
||||
initForm()
|
||||
})
|
||||
|
||||
return {
|
||||
formRef,
|
||||
formData,
|
||||
rules,
|
||||
loading,
|
||||
isPassing,
|
||||
isClickPass,
|
||||
mockAccounts,
|
||||
setupAccount,
|
||||
handleLogin,
|
||||
resetDragVerify
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user