feat: 登录页
This commit is contained in:
parent
02f9c4ec4c
commit
03b516afa7
|
|
@ -8,11 +8,10 @@ VITE_WX_APPID = 'wxa2abb91f64032a2b'
|
|||
VITE_APP_PUBLIC_BASE=/
|
||||
|
||||
# 登录页面
|
||||
VITE_LOGIN_URL = '/pages/login/index'
|
||||
# 第一个请求地址
|
||||
VITE_SERVER_BASEURL = 'https://ukw0y1.laf.run'
|
||||
VITE_LOGIN_URL = '/pages/auth/index'
|
||||
|
||||
VITE_UPLOAD_BASEURL = 'https://ukw0y1.laf.run/upload'
|
||||
VITE_SERVER_BASEURL = 'http://mapi.xianglexue.com/api/v1'
|
||||
VITE_UPLOAD_BASEURL = 'http://mapi.xianglexue.com/api/v1'
|
||||
|
||||
# h5是否需要配置代理
|
||||
VITE_APP_PROXY=false
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# 变量必须以 VITE_ 为前缀才能暴露给外部读取
|
||||
NODE_ENV = 'development'
|
||||
# 是否去除console 和 debugger
|
||||
VITE_DELETE_CONSOLE = true
|
||||
VITE_DELETE_CONSOLE = false
|
||||
# 是否开启sourcemap
|
||||
VITE_SHOW_SOURCEMAP = false
|
||||
|
|
|
|||
78
src/App.vue
78
src/App.vue
|
|
@ -1,25 +1,91 @@
|
|||
<script setup lang="ts">
|
||||
import { onHide, onLaunch, onShow } from '@dcloudio/uni-app'
|
||||
import { navigateToInterceptor } from '@/router/interceptor'
|
||||
import { useUserStore } from '@/store/user'
|
||||
import { tabbarStore } from './tabbar/store'
|
||||
import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only'
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 不需要登录验证的页面路径
|
||||
const publicPages = [
|
||||
'/pages/auth/splash',
|
||||
'/pages/auth/index',
|
||||
]
|
||||
|
||||
// 检查是否为公开页面
|
||||
function isPublicPage(path: string) {
|
||||
return publicPages.some(page => path.includes(page.replace('/pages/', '')))
|
||||
}
|
||||
|
||||
// 处理登录状态检查和页面跳转
|
||||
function handlePageNavigation(targetPath?: string) {
|
||||
const isLoggedIn = userStore.isLogin && userStore.accessToken
|
||||
|
||||
// 如果未登录且不是公开页面,跳转到加载页
|
||||
if (!isLoggedIn && targetPath && !isPublicPage(targetPath)) {
|
||||
console.log('用户未登录,跳转到加载页')
|
||||
uni.reLaunch({
|
||||
url: '/pages/auth/index',
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 如果已登录且访问的是登录相关页面,跳转到首页
|
||||
if (isLoggedIn && targetPath && isPublicPage(targetPath)) {
|
||||
console.log('用户已登录,跳转到首页')
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index',
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 正常处理页面跳转
|
||||
if (targetPath) {
|
||||
navigateToInterceptor.invoke({ url: targetPath })
|
||||
}
|
||||
else {
|
||||
// 根据登录状态决定默认跳转页面
|
||||
const defaultUrl = isLoggedIn ? '/pages/index/index' : '/pages/auth/splash'
|
||||
navigateToInterceptor.invoke({ url: defaultUrl })
|
||||
}
|
||||
}
|
||||
|
||||
onLaunch((options) => {
|
||||
// 处理直接进入页面路由的情况:如h5直接输入路由、微信小程序分享后进入等
|
||||
// https://github.com/unibest-tech/unibest/issues/192
|
||||
console.log('App Launch', options)
|
||||
if (options?.path) {
|
||||
navigateToInterceptor.invoke({ url: `/${options.path}` })
|
||||
}
|
||||
else {
|
||||
navigateToInterceptor.invoke({ url: '/' })
|
||||
}
|
||||
|
||||
const targetPath = options?.path ? `/${options.path}` : undefined
|
||||
|
||||
// 延迟执行以确保 store 已初始化
|
||||
setTimeout(() => {
|
||||
handlePageNavigation(targetPath)
|
||||
// 处理直接进入路由非首页时,tabbarIndex 不正确的问题
|
||||
tabbarStore.setAutoCurIdx(options.path)
|
||||
}, 100)
|
||||
})
|
||||
|
||||
onShow((options) => {
|
||||
console.log('App Show', options)
|
||||
|
||||
// 每次显示应用时检查登录状态
|
||||
const isLoggedIn = userStore.isLogin && userStore.accessToken
|
||||
if (!isLoggedIn) {
|
||||
// 检查当前页面是否为公开页面
|
||||
const pages = getCurrentPages()
|
||||
const currentPage = pages[pages.length - 1]
|
||||
const currentRoute = currentPage?.route || ''
|
||||
|
||||
if (!isPublicPage(`/${currentRoute}`)) {
|
||||
console.log('应用显示时检测到未登录,跳转到登录页')
|
||||
uni.reLaunch({
|
||||
url: '/pages/auth/index',
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
onHide(() => {
|
||||
console.log('App Hide')
|
||||
})
|
||||
|
|
|
|||
|
|
@ -0,0 +1,287 @@
|
|||
<script setup lang="ts">
|
||||
import type { LoginRequest } from '@/service/types'
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import VerificationCode from './VerificationCode.vue'
|
||||
|
||||
interface Props {
|
||||
mode: 'login' | 'reset'
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
(e: 'login', data: LoginRequest): void
|
||||
(e: 'reset', data: { phone: string, code: string, password: string }): void
|
||||
(e: 'switchMode', mode: 'login' | 'reset'): void
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
// 表单数据
|
||||
const loginForm = reactive<LoginRequest>({
|
||||
username: '',
|
||||
password: '',
|
||||
})
|
||||
|
||||
const resetForm = reactive({
|
||||
phone: '',
|
||||
code: '',
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
})
|
||||
|
||||
// 状态管理
|
||||
const loading = ref(false)
|
||||
const agreed = ref(false)
|
||||
|
||||
// 计算属性
|
||||
const isLogin = computed(() => props.mode === 'login')
|
||||
const isReset = computed(() => props.mode === 'reset')
|
||||
|
||||
// 表单验证
|
||||
function validateLoginForm() {
|
||||
if (!loginForm.username) {
|
||||
uni.showToast({
|
||||
title: '请输入手机号',
|
||||
icon: 'none',
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
if (!/^1[3-9]\d{9}$/.test(loginForm.username)) {
|
||||
uni.showToast({
|
||||
title: '请输入正确的手机号',
|
||||
icon: 'none',
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
if (!loginForm.password) {
|
||||
uni.showToast({
|
||||
title: '请输入密码',
|
||||
icon: 'none',
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
if (loginForm.password.length < 6) {
|
||||
uni.showToast({
|
||||
title: '密码不能少于6位',
|
||||
icon: 'none',
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
function validateResetForm() {
|
||||
if (!resetForm.phone) {
|
||||
uni.showToast({
|
||||
title: '请输入手机号',
|
||||
icon: 'none',
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
if (!/^1[3-9]\d{9}$/.test(resetForm.phone)) {
|
||||
uni.showToast({
|
||||
title: '请输入正确的手机号',
|
||||
icon: 'none',
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
if (!resetForm.code) {
|
||||
uni.showToast({
|
||||
title: '请输入验证码',
|
||||
icon: 'none',
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
if (!resetForm.password) {
|
||||
uni.showToast({
|
||||
title: '请输入新密码',
|
||||
icon: 'none',
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
if (resetForm.password.length < 8) {
|
||||
uni.showToast({
|
||||
title: '密码不能少于8位',
|
||||
icon: 'none',
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
if (resetForm.password !== resetForm.confirmPassword) {
|
||||
uni.showToast({
|
||||
title: '两次密码输入不一致',
|
||||
icon: 'none',
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
if (!agreed.value) {
|
||||
uni.showToast({
|
||||
title: '请先同意用户协议',
|
||||
icon: 'none',
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// 事件处理
|
||||
function handleSubmit() {
|
||||
if (isLogin.value) {
|
||||
if (validateLoginForm()) {
|
||||
emit('login', loginForm)
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (validateResetForm()) {
|
||||
emit('reset', {
|
||||
phone: resetForm.phone,
|
||||
code: resetForm.code,
|
||||
password: resetForm.password,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleSwitchMode() {
|
||||
const newMode = isLogin.value ? 'reset' : 'login'
|
||||
emit('switchMode', newMode)
|
||||
}
|
||||
|
||||
// 验证码回调
|
||||
function handleCodeUpdate(code: string) {
|
||||
resetForm.code = code
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="min-h-40vh w-full p-8 pt-4">
|
||||
<!-- 表单标题 -->
|
||||
<view class="mb-4 text-center">
|
||||
<text class="text-xl text-gray-900 font-bold">{{ isLogin ? '登录' : '重置密码' }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 表单内容 -->
|
||||
<view class="space-y-4">
|
||||
<!-- 登录表单 -->
|
||||
<view v-if="isLogin" class="mb-24 space-y-4">
|
||||
<!-- 手机号输入 -->
|
||||
<view class="space-y-2">
|
||||
<text class="block text-sm text-gray-700 font-medium">手机号</text>
|
||||
<wd-input
|
||||
v-model="loginForm.username"
|
||||
placeholder="请输入手机号"
|
||||
type="number"
|
||||
:maxlength="11"
|
||||
clearable
|
||||
class="w-full"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 密码输入 -->
|
||||
<view class="space-y-2">
|
||||
<text class="block text-sm text-gray-700 font-medium">密码</text>
|
||||
<wd-input
|
||||
v-model="loginForm.password"
|
||||
type="text"
|
||||
show-password
|
||||
placeholder="请输入密码"
|
||||
clearable
|
||||
class="w-full"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 重置密码表单 -->
|
||||
<view v-else class="space-y-2">
|
||||
<!-- 手机号输入 -->
|
||||
<view class="space-y-2">
|
||||
<text class="block text-sm text-gray-700 font-medium">电话号码</text>
|
||||
<wd-input
|
||||
v-model="resetForm.phone"
|
||||
placeholder="请输入手机号"
|
||||
type="number"
|
||||
:maxlength="11"
|
||||
clearable
|
||||
class="w-full"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 验证码输入 -->
|
||||
<verification-code
|
||||
:phone="resetForm.phone"
|
||||
@update:code="handleCodeUpdate"
|
||||
/>
|
||||
|
||||
<!-- 新密码输入 -->
|
||||
<view class="space-y-2">
|
||||
<text class="block text-sm text-gray-700 font-medium">新密码</text>
|
||||
<wd-input
|
||||
v-model="resetForm.password"
|
||||
type="text"
|
||||
show-password
|
||||
placeholder="请输入新密码"
|
||||
clearable
|
||||
class="w-full"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 确认密码输入 -->
|
||||
<view class="space-y-2">
|
||||
<text class="block text-sm text-gray-700 font-medium">确认密码</text>
|
||||
<wd-input
|
||||
v-model="resetForm.confirmPassword"
|
||||
type="text"
|
||||
show-password
|
||||
placeholder="请再次输入密码"
|
||||
clearable
|
||||
class="w-full"
|
||||
/>
|
||||
<!-- 密码提示 -->
|
||||
<text class="block text-0.6rem text-gray-500">
|
||||
密码应不少于8位,至少包含数字、字母,且不能包含中文。
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 用户协议 -->
|
||||
<view class="flex items-center space-x-1" @click="agreed = !agreed">
|
||||
<wd-checkbox :model-value="agreed" class="mt-2" />
|
||||
<text class="text-0.6rem text-gray-600">
|
||||
我已阅读并同意《用户协议》、《隐私政策》,以及《个人信息处理规则》
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 表单按钮 -->
|
||||
<view class="mt-4 space-y-4">
|
||||
<!-- 提交按钮 -->
|
||||
<wd-button
|
||||
type="primary"
|
||||
size="large"
|
||||
block
|
||||
:loading="loading"
|
||||
class="rounded-lg !h-12"
|
||||
@click="handleSubmit"
|
||||
>
|
||||
{{ isLogin ? '登录' : '重置密码' }}
|
||||
</wd-button>
|
||||
|
||||
<!-- 切换模式 -->
|
||||
<view class="text-center">
|
||||
<text class="cursor-pointer text-sm text-blue-600" @click="handleSwitchMode">
|
||||
{{ isLogin ? '忘记密码?' : '返回登录' }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
import { authGetCodeUsingGet } from '@/service'
|
||||
|
||||
interface Props {
|
||||
phone: string
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
(e: 'update:code', code: string): void
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
// 状态管理
|
||||
const code = ref('')
|
||||
const disabled = ref(false)
|
||||
const countdown = ref(0)
|
||||
const codeText = ref('获取验证码')
|
||||
|
||||
// 监听验证码变化
|
||||
watch(code, (newCode) => {
|
||||
emit('update:code', newCode)
|
||||
})
|
||||
|
||||
// 发送验证码
|
||||
async function sendCode() {
|
||||
if (!props.phone) {
|
||||
uni.showToast({
|
||||
title: '请输入手机号',
|
||||
icon: 'none',
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (!/^1[3-9]\d{9}$/.test(props.phone)) {
|
||||
uni.showToast({
|
||||
title: '请输入正确的手机号',
|
||||
icon: 'none',
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await authGetCodeUsingGet({
|
||||
params: { phone: props.phone },
|
||||
})
|
||||
|
||||
uni.showToast({
|
||||
title: '验证码已发送',
|
||||
icon: 'success',
|
||||
})
|
||||
|
||||
// 开始倒计时
|
||||
startCountdown()
|
||||
}
|
||||
catch (error) {
|
||||
console.error('发送验证码失败:', error)
|
||||
uni.showToast({
|
||||
title: '发送失败,请重试',
|
||||
icon: 'none',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 开始倒计时
|
||||
function startCountdown() {
|
||||
disabled.value = true
|
||||
countdown.value = 60
|
||||
|
||||
const timer = setInterval(() => {
|
||||
countdown.value--
|
||||
codeText.value = `${countdown.value}s后重发`
|
||||
|
||||
if (countdown.value <= 0) {
|
||||
clearInterval(timer)
|
||||
disabled.value = false
|
||||
codeText.value = '获取验证码'
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 重新获取验证码的提示
|
||||
function handleNoCode() {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '如果您收不到验证码,请检查手机号是否正确,或联系客服获取帮助。',
|
||||
showCancel: false,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="space-y-2">
|
||||
<text class="block text-sm text-gray-700 font-medium">验证码</text>
|
||||
<view class="flex space-x-3">
|
||||
<wd-input
|
||||
v-model="code"
|
||||
placeholder="请输入验证码"
|
||||
type="number"
|
||||
:maxlength="6"
|
||||
clearable
|
||||
class="flex-1"
|
||||
/>
|
||||
<wd-button
|
||||
type="primary"
|
||||
size="small"
|
||||
:disabled="disabled"
|
||||
class="h-10 whitespace-nowrap px-4 text-xs"
|
||||
@click="sendCode"
|
||||
>
|
||||
{{ codeText }}
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
|
@ -68,6 +68,8 @@ const httpInterceptor = {
|
|||
if (currentToken) {
|
||||
options.header.Authorization = `Bearer ${currentToken}`
|
||||
}
|
||||
|
||||
return options
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,6 +72,14 @@
|
|||
"style": {
|
||||
"navigationBarTitleText": "Vue Query 请求演示"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/auth/index",
|
||||
"type": "page",
|
||||
"name": "auth",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
}
|
||||
],
|
||||
"subPackages": [
|
||||
|
|
|
|||
|
|
@ -0,0 +1,140 @@
|
|||
<script setup lang="ts">
|
||||
import type { LoginRequest } from '@/service/types'
|
||||
import { ref } from 'vue'
|
||||
import AuthForm from '@/components/auth/AuthForm.vue'
|
||||
import { sysUsersResetPasswordUsingPost } from '@/service/xitongyonghu'
|
||||
import { useUserStore } from '@/store/user'
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 当前模式:登录或重置密码
|
||||
const currentMode = ref<'login' | 'reset'>('login')
|
||||
const loading = ref(false)
|
||||
|
||||
// 处理登录
|
||||
async function handleLogin(data: LoginRequest) {
|
||||
try {
|
||||
loading.value = true
|
||||
await userStore.login(data)
|
||||
|
||||
uni.showToast({
|
||||
title: '登录成功',
|
||||
icon: 'success',
|
||||
})
|
||||
|
||||
// 登录成功,跳转到首页
|
||||
setTimeout(() => {
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index',
|
||||
})
|
||||
}, 1500)
|
||||
}
|
||||
catch (error) {
|
||||
console.error('登录失败:', error)
|
||||
}
|
||||
finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 处理重置密码
|
||||
async function handleReset(data: { phone: string, code: string, password: string }) {
|
||||
try {
|
||||
loading.value = true
|
||||
|
||||
// 调用重置密码API
|
||||
await sysUsersResetPasswordUsingPost({
|
||||
body: {
|
||||
phone: data.phone,
|
||||
verify_code: data.code,
|
||||
new_password: data.password,
|
||||
confirm_password: data.password,
|
||||
username: data.phone, // 使用手机号作为用户名
|
||||
},
|
||||
})
|
||||
|
||||
uni.showToast({
|
||||
title: '密码重置成功',
|
||||
icon: 'success',
|
||||
})
|
||||
|
||||
// 延迟切换到登录模式
|
||||
setTimeout(() => {
|
||||
currentMode.value = 'login'
|
||||
}, 1500)
|
||||
}
|
||||
catch (error) {
|
||||
console.error('重置密码失败:', error)
|
||||
uni.showToast({
|
||||
title: '重置失败,请重试',
|
||||
icon: 'none',
|
||||
})
|
||||
}
|
||||
finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 切换模式
|
||||
function handleSwitchMode(mode: 'login' | 'reset') {
|
||||
currentMode.value = mode
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="relative h-screen w-full overflow-hidden from-blue-500 via-purple-500 to-blue-600 bg-gradient-to-br">
|
||||
<!-- 背景图片 -->
|
||||
<image
|
||||
class="absolute inset-0 z-0 h-full w-full opacity-80"
|
||||
src="https://images.unsplash.com/photo-1557804506-669a67965ba0?ixlib=rb-4.0.3&auto=format&fit=crop&w=1974&q=80"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
|
||||
<!-- 渐变蒙版 -->
|
||||
<view class="absolute inset-0 z-1 from-blue-500/90 via-purple-500/80 to-blue-600/90 bg-gradient-to-br" />
|
||||
|
||||
<!-- 主要内容 -->
|
||||
<view class="relative z-2 h-full flex flex-col">
|
||||
<!-- Logo 区域 -->
|
||||
<view class="flex flex-1 flex-col items-center justify-center px-8">
|
||||
<view class="relative mb-4">
|
||||
<view class="h-12 w-12 flex items-center justify-center rounded-3xl from-red-500 to-red-600 bg-gradient-to-br shadow-xl">
|
||||
<text class="text-3xl text-white font-bold">享</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="text-center">
|
||||
<text class="mb-2 block text-4xl text-white font-bold drop-shadow-lg">象乐学</text>
|
||||
<text class="mb-4 block text-base text-white/90 drop-shadow">【教师版】</text>
|
||||
<text class="block text-sm text-white/80 drop-shadow">乐学未来,向学而行</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 认证表单区域 - 全宽底部 -->
|
||||
<view class="w-full rounded-t-2xl bg-white shadow-2xl">
|
||||
<auth-form
|
||||
:mode="currentMode"
|
||||
@login="handleLogin"
|
||||
@reset="handleReset"
|
||||
@switch-mode="handleSwitchMode"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 装饰元素 -->
|
||||
<view class="pointer-events-none absolute inset-0 z-1">
|
||||
<view class="absolute left-1/10 top-1/5 h-20 w-20 animate-pulse rounded-full bg-white/10" />
|
||||
<view class="animation-delay-2s absolute right-1/6 top-3/5 h-12 w-12 animate-pulse rounded-full bg-white/10" />
|
||||
<view class="animation-delay-4s absolute left-1/12 top-3/4 h-28 w-28 animate-pulse rounded-full bg-white/10" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<route lang="json5">
|
||||
{
|
||||
"name": "auth",
|
||||
"style": {
|
||||
"navigationStyle": "custom",
|
||||
}
|
||||
}
|
||||
</route>
|
||||
Loading…
Reference in New Issue