feat(登录): 新增AB98登录功能及相关路由和状态管理
添加了AB98登录页面、路由配置、白名单管理、用户状态存储及API接口,实现了手机验证码登录功能。同时更新了用户信息展示逻辑,确保登录后正确显示用户信息。
This commit is contained in:
parent
533a94ca9b
commit
7a9847bb25
|
@ -0,0 +1,55 @@
|
||||||
|
import { request } from '@/http/axios'
|
||||||
|
import {
|
||||||
|
GetTokenParams,
|
||||||
|
LoginData,
|
||||||
|
LogoutResponse,
|
||||||
|
SmsSendResponse,
|
||||||
|
TokenResponse,
|
||||||
|
VerifySmsParams,
|
||||||
|
WechatQrCodeParams
|
||||||
|
} from './type'
|
||||||
|
|
||||||
|
/** 获取临时令牌 */
|
||||||
|
export function getTokenApi(appName: string) {
|
||||||
|
return request<ApiResponseData<TokenResponse>>({
|
||||||
|
url: '/api/wx/login/getToken',
|
||||||
|
method: 'get',
|
||||||
|
params: { appName }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取微信登录二维码 */
|
||||||
|
export function getWechatQrCodeApi(token: string) {
|
||||||
|
return request<ApiResponseData<string>>({
|
||||||
|
url: '/api/wx/login/wechat/qrcode',
|
||||||
|
method: 'get',
|
||||||
|
params: { token }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 发送短信验证码 */
|
||||||
|
export function sendSmsApi(token: string, tel: string) {
|
||||||
|
return request<ApiResponseData<SmsSendResponse>>({
|
||||||
|
url: '/api/wx/login/sendSms',
|
||||||
|
method: 'post',
|
||||||
|
params: { token, tel }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 验证短信验证码 */
|
||||||
|
export function verifySmsApi(params: VerifySmsParams) {
|
||||||
|
return request<ApiResponseData<LoginData>>({
|
||||||
|
url: '/api/wx/login/verifySms',
|
||||||
|
method: 'post',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 用户退出登录 */
|
||||||
|
export function logoutApi(token: string) {
|
||||||
|
return request<ApiResponseData<LogoutResponse>>({
|
||||||
|
url: '/api/wx/login/logout',
|
||||||
|
method: 'post',
|
||||||
|
params: { token }
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
/** 令牌响应 */
|
||||||
|
export interface TokenResponse {
|
||||||
|
/** 认证令牌 */
|
||||||
|
token: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 退出登录响应 */
|
||||||
|
export interface LogoutResponse {
|
||||||
|
/** 是否成功 */
|
||||||
|
success: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 短信发送响应 */
|
||||||
|
export interface SmsSendResponse {
|
||||||
|
/** 发送状态 */
|
||||||
|
success: boolean
|
||||||
|
/** 错误信息 */
|
||||||
|
message?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 登录数据 */
|
||||||
|
export interface LoginData {
|
||||||
|
/** 用户头像 */
|
||||||
|
face_img: string
|
||||||
|
/** 登录状态 */
|
||||||
|
success: boolean
|
||||||
|
/** 用户性别 */
|
||||||
|
sex: string
|
||||||
|
/** 用户姓名 */
|
||||||
|
name: string
|
||||||
|
/** 用户ID */
|
||||||
|
userid: string
|
||||||
|
/** 是否已注册 */
|
||||||
|
registered: boolean
|
||||||
|
/** 联系电话 */
|
||||||
|
tel: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取令牌参数 */
|
||||||
|
export type GetTokenParams = {
|
||||||
|
/** 应用名称 */
|
||||||
|
appName: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 微信二维码参数 */
|
||||||
|
export type WechatQrCodeParams = {
|
||||||
|
/** 认证令牌 */
|
||||||
|
token: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 短信验证参数 */
|
||||||
|
export type VerifySmsParams = {
|
||||||
|
/** 认证令牌 */
|
||||||
|
token: string
|
||||||
|
/** 手机号码 */
|
||||||
|
tel: string
|
||||||
|
/** 验证码 */
|
||||||
|
vcode: string
|
||||||
|
}
|
|
@ -3,7 +3,7 @@ const router = useRouter()
|
||||||
|
|
||||||
const tabbarItemList = computed(() => {
|
const tabbarItemList = computed(() => {
|
||||||
const routes = router.getRoutes()
|
const routes = router.getRoutes()
|
||||||
return routes.filter(route => route.meta.layout?.tabbar?.showTabbar)
|
return routes.filter(route => route.meta.layout?.tabbar?.showTabbar && route.path !== '/cabinet')
|
||||||
.map(route => ({
|
.map(route => ({
|
||||||
title: route.meta.title,
|
title: route.meta.title,
|
||||||
icon: route.meta.layout?.tabbar?.icon,
|
icon: route.meta.layout?.tabbar?.icon,
|
||||||
|
|
|
@ -0,0 +1,168 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { verifySmsApi, sendSmsApi, getTokenApi } from '@/common/apis/ab98'
|
||||||
|
import { useAb98UserStore } from '@/pinia/stores/ab98-user'
|
||||||
|
import { showSuccessToast, showFailToast } from 'vant'
|
||||||
|
|
||||||
|
const userStore = useAb98UserStore()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
// 表单数据
|
||||||
|
const form = ref({
|
||||||
|
tel: '',
|
||||||
|
vcode: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
// 验证规则
|
||||||
|
const rules = {
|
||||||
|
tel: [
|
||||||
|
{ required: true, message: '请输入手机号码', trigger: 'blur' },
|
||||||
|
{ pattern: /^1[3-9]\d{9}$/, message: '手机号格式不正确', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
vcode: [
|
||||||
|
{ required: true, message: '请输入验证码', trigger: 'blur' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 倒计时状态
|
||||||
|
const countdown = ref(0)
|
||||||
|
const canSend = ref(true)
|
||||||
|
|
||||||
|
// 发送验证码
|
||||||
|
const handleSendSms = async () => {
|
||||||
|
if (!form.value.tel) {
|
||||||
|
showFailToast('请先输入手机号码')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { data: tokenData } = await getTokenApi('shop-web')
|
||||||
|
if (!tokenData?.success) {
|
||||||
|
showFailToast('获取token失败')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userStore.setToken(tokenData.data.token);
|
||||||
|
|
||||||
|
const { data } = await sendSmsApi(tokenData.data.token, form.value.tel)
|
||||||
|
if (data.success) {
|
||||||
|
showSuccessToast('验证码已发送')
|
||||||
|
startCountdown()
|
||||||
|
} else {
|
||||||
|
showFailToast(data.message || '发送失败')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
showFailToast('发送验证码失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始倒计时
|
||||||
|
const startCountdown = () => {
|
||||||
|
canSend.value = false
|
||||||
|
countdown.value = 60
|
||||||
|
const timer = setInterval(() => {
|
||||||
|
if (countdown.value <= 0) {
|
||||||
|
clearInterval(timer)
|
||||||
|
canSend.value = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
countdown.value--
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交登录
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
token: userStore.token,
|
||||||
|
tel: form.value.tel,
|
||||||
|
vcode: form.value.vcode
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data } = await verifySmsApi(params)
|
||||||
|
if (data.success) {
|
||||||
|
userStore.setUserInfo(data)
|
||||||
|
ElMessage.success('登录成功')
|
||||||
|
router.push('/')
|
||||||
|
} else {
|
||||||
|
ElMessage.error('验证码错误或已过期')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('登录失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="login-container">
|
||||||
|
<el-card class="login-box">
|
||||||
|
<h2 class="title">手机验证码登录</h2>
|
||||||
|
|
||||||
|
<el-form
|
||||||
|
:model="form"
|
||||||
|
:rules="rules"
|
||||||
|
label-width="80px"
|
||||||
|
label-position="top"
|
||||||
|
>
|
||||||
|
<el-form-item label="手机号码" prop="tel">
|
||||||
|
<el-input v-model="form.tel" placeholder="请输入手机号码" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="验证码" prop="vcode">
|
||||||
|
<div class="vcode-input">
|
||||||
|
<el-input
|
||||||
|
v-model="form.vcode"
|
||||||
|
placeholder="请输入验证码"
|
||||||
|
style="width: 60%"
|
||||||
|
/>
|
||||||
|
<el-button
|
||||||
|
:disabled="!canSend"
|
||||||
|
@click="handleSendSms"
|
||||||
|
style="margin-left: 10px; width: 35%"
|
||||||
|
>
|
||||||
|
{{ countdown > 0 ? `${countdown}秒后重试` : '获取验证码' }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
@click="handleSubmit"
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
立即登录
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.login-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-box {
|
||||||
|
width: 400px;
|
||||||
|
padding: 30px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vcode-input {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,17 +1,22 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { useWxStore } from '@/pinia/stores/wx'
|
import { useWxStore } from '@/pinia/stores/wx'
|
||||||
import { computed } from 'vue'
|
import { useAb98UserStore } from '@/pinia/stores/ab98-user'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
import { publicPath } from "@/common/utils/path"
|
import { publicPath } from "@/common/utils/path"
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const wxStore = useWxStore()
|
const wxStore = useWxStore()
|
||||||
const balance = computed(() => wxStore.balance)
|
const ab98UserStore = useAb98UserStore()
|
||||||
|
|
||||||
|
const { balance } = storeToRefs(wxStore)
|
||||||
|
const { name: userName, sex: userSex, face_img } = storeToRefs(ab98UserStore)
|
||||||
|
|
||||||
|
const userAvatar = face_img.value ? face_img.value : `${publicPath}img/1.jpg`
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div un-py-16px>
|
<div un-py-16px>
|
||||||
<!-- 用户信息区域 -->
|
|
||||||
<van-cell-group class="user-card">
|
<van-cell-group class="user-card">
|
||||||
<van-cell :border="false">
|
<van-cell :border="false">
|
||||||
<template #title>
|
<template #title>
|
||||||
|
@ -20,13 +25,12 @@ const balance = computed(() => wxStore.balance)
|
||||||
round
|
round
|
||||||
width="80"
|
width="80"
|
||||||
height="80"
|
height="80"
|
||||||
:src="`${publicPath}img/1.jpg`"
|
:src="userAvatar"
|
||||||
class="mr-4"
|
class="mr-4"
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<div class="text-lg font-bold mb-2">{{ '' }}</div>
|
<div class="text-lg font-bold mb-2">{{ userName }}</div>
|
||||||
<van-tag type="primary" class="mr-2">{{ 20 }}岁</van-tag>
|
<van-tag type="primary" class="mr-2">{{ userSex }}</van-tag>
|
||||||
<van-tag type="success">{{ '男' }}</van-tag>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -155,7 +155,7 @@ async function handleSubmit() {
|
||||||
<van-field label="支付方式" :model-value="selectedPayment" readonly>
|
<van-field label="支付方式" :model-value="selectedPayment" readonly>
|
||||||
<template #input>
|
<template #input>
|
||||||
<van-radio-group v-model="selectedPayment" direction="horizontal">
|
<van-radio-group v-model="selectedPayment" direction="horizontal">
|
||||||
<van-radio name="wechat">
|
<van-radio name="wechat" v-if="!wxStore.corpid">
|
||||||
<van-icon name="wechat" class="method-icon" />
|
<van-icon name="wechat" class="method-icon" />
|
||||||
微信支付
|
微信支付
|
||||||
</van-radio>
|
</van-radio>
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
import { pinia } from "@/pinia"
|
||||||
|
import { LoginData } from "@/common/apis/ab98/type"
|
||||||
|
|
||||||
|
// 本地存储键名常量
|
||||||
|
const STORAGE_KEYS = {
|
||||||
|
FACE: 'ab98_face',
|
||||||
|
SEX: 'ab98_sex',
|
||||||
|
NAME: 'ab98_name',
|
||||||
|
USERID: 'ab98_userid',
|
||||||
|
REGISTERED: 'ab98_registered',
|
||||||
|
TEL: 'ab98_tel',
|
||||||
|
TOKEN: 'ab98_token'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AB98用户信息存储
|
||||||
|
* @description 管理AB98系统用户相关状态信息
|
||||||
|
*/
|
||||||
|
export const useAb98UserStore = defineStore("ab98User", () => {
|
||||||
|
// 用户面部图像URL
|
||||||
|
const storedFace = localStorage.getItem(STORAGE_KEYS.FACE)
|
||||||
|
const face_img = ref<string>(storedFace ? atob(storedFace) : '')
|
||||||
|
// 用户性别(男/女)
|
||||||
|
const storedSex = localStorage.getItem(STORAGE_KEYS.SEX)
|
||||||
|
const sex = ref<string>(storedSex ? atob(storedSex) : '')
|
||||||
|
// 用户真实姓名
|
||||||
|
const storedName = localStorage.getItem(STORAGE_KEYS.NAME)
|
||||||
|
const name = ref<string>(storedName ? atob(storedName) : '')
|
||||||
|
// AB98系统用户唯一标识
|
||||||
|
const storedUserId = localStorage.getItem(STORAGE_KEYS.USERID)
|
||||||
|
const userid = ref<string>(storedUserId ? atob(storedUserId) : "")
|
||||||
|
// 是否已完成注册流程
|
||||||
|
const registered = ref<boolean>(JSON.parse(localStorage.getItem(STORAGE_KEYS.REGISTERED) || "false"))
|
||||||
|
// 用户绑定手机号
|
||||||
|
const storedTel = localStorage.getItem(STORAGE_KEYS.TEL)
|
||||||
|
const tel = ref<string>(storedTel ? atob(storedTel) : "")
|
||||||
|
// 用户认证令牌
|
||||||
|
const storedToken = localStorage.getItem(STORAGE_KEYS.TOKEN)
|
||||||
|
const token = ref<string>(storedToken ? atob(storedToken) : "")
|
||||||
|
// 用户登录状态
|
||||||
|
const isLogin = ref<boolean>(false);
|
||||||
|
isLogin.value = tel.value ? true : false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新用户基本信息
|
||||||
|
* @param data - 登录接口返回的用户数据
|
||||||
|
*/
|
||||||
|
const setUserInfo = (data: LoginData) => {
|
||||||
|
face_img.value = data.face_img
|
||||||
|
localStorage.setItem(STORAGE_KEYS.FACE, btoa(data.face_img))
|
||||||
|
sex.value = data.sex
|
||||||
|
localStorage.setItem(STORAGE_KEYS.SEX, btoa(data.sex))
|
||||||
|
name.value = data.name
|
||||||
|
localStorage.setItem(STORAGE_KEYS.NAME, btoa(data.name))
|
||||||
|
userid.value = data.userid
|
||||||
|
localStorage.setItem(STORAGE_KEYS.USERID, btoa(data.userid))
|
||||||
|
registered.value = data.registered
|
||||||
|
localStorage.setItem(STORAGE_KEYS.REGISTERED, JSON.stringify(data.registered))
|
||||||
|
tel.value = data.tel
|
||||||
|
localStorage.setItem(STORAGE_KEYS.TEL, btoa(data.tel))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空用户敏感信息
|
||||||
|
* @description 用于用户登出或会话过期时
|
||||||
|
*/
|
||||||
|
const clearUserInfo = () => {
|
||||||
|
face_img.value = ""
|
||||||
|
localStorage.removeItem(STORAGE_KEYS.FACE)
|
||||||
|
sex.value = ""
|
||||||
|
localStorage.removeItem(STORAGE_KEYS.SEX)
|
||||||
|
name.value = ""
|
||||||
|
localStorage.removeItem(STORAGE_KEYS.NAME)
|
||||||
|
userid.value = ""
|
||||||
|
localStorage.removeItem(STORAGE_KEYS.USERID)
|
||||||
|
registered.value = false
|
||||||
|
localStorage.removeItem(STORAGE_KEYS.REGISTERED)
|
||||||
|
tel.value = ""
|
||||||
|
localStorage.removeItem(STORAGE_KEYS.TEL)
|
||||||
|
localStorage.removeItem(STORAGE_KEYS.TOKEN)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置认证令牌
|
||||||
|
* @param value - JWT格式的认证令牌
|
||||||
|
*/
|
||||||
|
const setToken = (value: string) => {
|
||||||
|
localStorage.setItem(STORAGE_KEYS.TOKEN, btoa(value))
|
||||||
|
token.value = value
|
||||||
|
}
|
||||||
|
|
||||||
|
const setTel = (value: string) => {
|
||||||
|
localStorage.setItem(STORAGE_KEYS.TEL, btoa(value))
|
||||||
|
tel.value = value
|
||||||
|
}
|
||||||
|
|
||||||
|
const setIsLogin = (value: boolean) => {
|
||||||
|
isLogin.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
face_img,
|
||||||
|
sex,
|
||||||
|
name,
|
||||||
|
userid,
|
||||||
|
registered,
|
||||||
|
tel,
|
||||||
|
token,
|
||||||
|
isLogin,
|
||||||
|
setUserInfo,
|
||||||
|
setToken,
|
||||||
|
setTel,
|
||||||
|
setIsLogin,
|
||||||
|
clearUserInfo
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 在非setup上下文或SSR场景中使用store
|
||||||
|
*/
|
||||||
|
export function useAb98UserStoreOutside() {
|
||||||
|
return useAb98UserStore(pinia)
|
||||||
|
}
|
|
@ -5,18 +5,26 @@ import { isWhiteList } from "@/router/whitelist"
|
||||||
import { useTitle } from "@@/composables/useTitle"
|
import { useTitle } from "@@/composables/useTitle"
|
||||||
import { getToken } from "@@/utils/cache/cookies"
|
import { getToken } from "@@/utils/cache/cookies"
|
||||||
import NProgress from "nprogress"
|
import NProgress from "nprogress"
|
||||||
|
import { useAb98UserStore } from '@/pinia/stores/ab98-user'
|
||||||
|
|
||||||
|
|
||||||
NProgress.configure({ showSpinner: false })
|
NProgress.configure({ showSpinner: false })
|
||||||
|
|
||||||
const { setTitle } = useTitle()
|
const { setTitle } = useTitle()
|
||||||
|
|
||||||
const LOGIN_PATH = "/login"
|
const LOGIN_PATH = "/ab98"
|
||||||
|
|
||||||
export function registerNavigationGuard(router: Router) {
|
export function registerNavigationGuard(router: Router) {
|
||||||
// 全局前置守卫
|
// 全局前置守卫
|
||||||
router.beforeEach((to, _from) => {
|
router.beforeEach((to, _from) => {
|
||||||
NProgress.start()
|
NProgress.start()
|
||||||
|
const userStore = useAb98UserStore()
|
||||||
|
if (!userStore.isLogin) {
|
||||||
|
// 如果在免登录的白名单中,则直接进入
|
||||||
|
if (isWhiteList(to)) return true
|
||||||
|
// 其他没有访问权限的页面将被重定向到登录页面
|
||||||
|
return LOGIN_PATH
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
// const userStore = useUserStore()
|
// const userStore = useUserStore()
|
||||||
// // 如果没有登录
|
// // 如果没有登录
|
||||||
|
|
|
@ -86,7 +86,7 @@ export const routes: RouteRecordRaw[] = [
|
||||||
showLeftArrow: false
|
showLeftArrow: false
|
||||||
},
|
},
|
||||||
tabbar: {
|
tabbar: {
|
||||||
showTabbar: false,
|
showTabbar: true,
|
||||||
icon: "home-o"
|
icon: "home-o"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,6 +147,14 @@ export const routes: RouteRecordRaw[] = [
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/ab98",
|
||||||
|
component: () => import("@/pages/login/Ab98Login.vue"),
|
||||||
|
name: "Ab98Login",
|
||||||
|
meta: {
|
||||||
|
title: "登录"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type { RouteLocationNormalizedGeneric, RouteRecordNameGeneric } from "vue-router"
|
import type { RouteLocationNormalizedGeneric, RouteRecordNameGeneric } from "vue-router"
|
||||||
|
|
||||||
/** 免登录白名单(匹配路由 path) */
|
/** 免登录白名单(匹配路由 path) */
|
||||||
const whiteListByPath: string[] = ["/login"]
|
const whiteListByPath: string[] = ["/login", "/ab98"]
|
||||||
|
|
||||||
/** 免登录白名单(匹配路由 name) */
|
/** 免登录白名单(匹配路由 name) */
|
||||||
const whiteListByName: RouteRecordNameGeneric[] = []
|
const whiteListByName: RouteRecordNameGeneric[] = []
|
||||||
|
|
Loading…
Reference in New Issue