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:
sexygoat
2026-01-22 16:35:33 +08:00
commit 222e5bb11a
495 changed files with 145440 additions and 0 deletions

273
src/composables/useLogin.ts Normal file
View 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
}
}