Toggle navigation
Toggle navigation
This project
Loading...
Sign in
Hooke
/
mlaj
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Snippets
Network
Create a new issue
Builds
Commits
Issue Boards
Authored by
hookehuyr
2026-01-31 21:48:05 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
3a1974d85dbb226c17be6ef9ecfee7d44c07868e
3a1974d8
1 parent
e0ce3081
fix: 更新登录页面图标链接
更新美乐爱觉教育登录页面的品牌图标,使用新版本的logo图片地址。
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
108 additions
and
97 deletions
src/views/auth/LoginPage.vue
src/views/auth/LoginPage.vue
View file @
3a1974d
<template>
<div
class="
min-h-screen flex flex-col bg-gradient-to-br from-green-50 via-teal-50 to-blue-50 py-8 px-4
sm:px-6 lg:px-8"
class="
flex min-h-screen flex-col bg-gradient-to-br from-green-50 via-teal-50 to-blue-50 px-4 py-8
sm:px-6 lg:px-8"
>
<div class="sm:mx-auto sm:w-full sm:max-w-md text-center">
<van-icon name="https://cdn.ipadbiz.cn/mlaj/icon/behalo-logo-1.png?imageMogr2/thumbnail/200x/strip/quality/70" size="10rem" style="margin-bottom: 0.5rem;" />
<h1 class="text-center text-3xl font-bold text-gray-800 mb-2">美乐爱觉教育</h1>
<div class="text-center sm:mx-auto sm:w-full sm:max-w-md">
<van-icon
name="https://cdn.ipadbiz.cn/mlaj/icon/behalo-logo-2.png?imageMogr2/thumbnail/200x/strip/quality/70"
size="10rem"
style="margin-bottom: 0.5rem"
/>
<h1 class="mb-2 text-center text-3xl font-bold text-gray-800">美乐爱觉教育</h1>
<!-- <h2 class="text-center text-xl font-medium text-gray-600">欢迎回来</h2> -->
</div>
<div class="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
<FrostedGlass class="
py-8 px-6 rounded-lg
">
<FrostedGlass class="
rounded-lg px-6 py-8
">
<div
v-if="error"
class="mb-4
bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded-md
"
class="mb-4
rounded-md border border-red-400 bg-red-100 px-4 py-3 text-red-700
"
>
{{ error }}
</div>
...
...
@@ -35,7 +39,7 @@
@input="mobile = $event.target.value.replace(/\D/g, '')"
@focus="handleInputFocus"
@blur="validatePhone"
class="mt-1 block w-full
px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-green-500 focus:border
-green-500"
class="mt-1 block w-full
rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-green-500 focus:outline-none focus:ring
-green-500"
/>
</div>
...
...
@@ -51,7 +55,7 @@
autocomplete="current-password"
required
placeholder="请输入6位密码"
class="mt-1 block w-full
px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-green-500 focus:border
-green-500"
class="mt-1 block w-full
rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-green-500 focus:outline-none focus:ring
-green-500"
/>
</div>
...
...
@@ -67,13 +71,13 @@
required
maxlength="6"
placeholder="请输入验证码"
class="mt-1 block w-full
px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-green-500 focus:border
-green-500"
class="mt-1 block w-full
rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-green-500 focus:outline-none focus:ring
-green-500"
/>
<button
type="button"
:disabled="countdown > 0 || !isPhoneValid"
@click="sendVerificationCode"
class="mt-1
px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap
"
class="mt-1
whitespace-nowrap rounded-md border border-transparent bg-green-600 px-4 py-2 text-sm font-medium text-white hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50
"
>
{{ countdown > 0 ? `${countdown}秒后重试` : '获取验证码' }}
</button>
...
...
@@ -104,10 +108,10 @@
<button
type="submit"
:disabled="loading"
class="
w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-gradient-to-r from-green-500 to-green-600 hover:from-green-600 hover:to-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500
"
:class="{ '
opacity-70 cursor-not-allowed
': loading }"
class="
flex w-full justify-center rounded-md border border-transparent bg-gradient-to-r from-green-500 to-green-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:from-green-600 hover:to-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2
"
:class="{ '
cursor-not-allowed opacity-70
': loading }"
>
{{ loading ?
"登录中..." : "登录/注册BEHALO宇宙账号"
}}
{{ loading ?
'登录中...' : '登录/注册BEHALO宇宙账号'
}}
</button>
</div>
</form>
...
...
@@ -157,11 +161,11 @@
</router-link>
</p>
</div> -->
<div class="
text-center mt-6
">
<div class="
mt-6 text-center
">
<p class="text-sm text-gray-600">
登录即表示同意
<span
class="
font-medium text-green-600 hover:text-green-500 cursor-pointer
"
class="
cursor-pointer font-medium text-green-600 hover:text-green-500
"
@click="userAgreementRef.openAgreement()"
>
《美乐爱觉宇宙用户协议》
...
...
@@ -170,10 +174,15 @@
</p>
</div>
<div class="mt-6 flex
justify-center items-center gap-4" style="flex-direction: column;
">
<div class="mt-6 flex
items-center justify-center gap-4" style="flex-direction: column
">
<div class="text-sm font-medium text-gray-600">其他登录方式</div>
<div>
<img :src="weixinLogo" alt="微信登录" style="width: 40px; height: 40px; border-radius: 8px;" @click="handleWxLoginClick">
<img
:src="weixinLogo"
alt="微信登录"
style="width: 40px; height: 40px; border-radius: 8px"
@click="handleWxLoginClick"
/>
</div>
</div>
</FrostedGlass>
...
...
@@ -182,74 +191,74 @@
</template>
<script setup>
import { ref } from
"vue";
import { useRoute, useRouter } from
"vue-router";
import FrostedGlass from
"@/components/effects/FrostedGlass.vue";
import { useAuth } from
"@/contexts/auth";
import { loginAPI, getUserInfoAPI } from
"@/api/users";
import { useTitle } from
"@vueuse/core";
import { smsAPI } from
"@/api/common";
import { showToast } from
"vant";
import UserAgreement from
"@/components/common/UserAgreement.vue";
import { setAuthHeaders } from
"@/utils/axios";
import { applyUserInfoAuth } from
"@/utils/auth_user_info";
import { ref } from
'vue'
import { useRoute, useRouter } from
'vue-router'
import FrostedGlass from
'@/components/effects/FrostedGlass.vue'
import { useAuth } from
'@/contexts/auth'
import { loginAPI, getUserInfoAPI } from
'@/api/users'
import { useTitle } from
'@vueuse/core'
import { smsAPI } from
'@/api/common'
import { showToast } from
'vant'
import UserAgreement from
'@/components/common/UserAgreement.vue'
import { setAuthHeaders } from
'@/utils/axios'
import { applyUserInfoAuth } from
'@/utils/auth_user_info'
import weixinLogo from '@/assets/images/weixin_logo_lg.jpeg'
import { startWxAuth } from '@/router/guards'
import { wxInfo } from '@/utils/tools'
const userAgreementRef = ref(null)
;
const userAgreementRef = ref(null)
const handleInputFocus = () => {
setTimeout(() => {
// 使用平滑滚动将页面向上移动200px(根据实际按钮区域高度调整)
window.scrollTo({
top: 150,
behavior: 'smooth'
})
;
}, 100)
;
}
;
const $route = useRoute()
;
useTitle($route.meta.title)
;
const router = useRouter()
;
const { login } = useAuth()
;
const mobile = ref(
"");
const password = ref(
"");
const verificationCode = ref(
"");
const error = ref(
"");
const loading = ref(false)
;
const isVerifyCodeLogin = ref(true)
;
const countdown = ref(0)
;
const isPhoneValid = ref(false)
;
behavior: 'smooth'
,
})
}, 100)
}
const $route = useRoute()
useTitle($route.meta.title)
const router = useRouter()
const { login } = useAuth()
const mobile = ref(
'')
const password = ref(
'')
const verificationCode = ref(
'')
const error = ref(
'')
const loading = ref(false)
const isVerifyCodeLogin = ref(true)
const countdown = ref(0)
const isPhoneValid = ref(false)
const validatePhone = () => {
if (!mobile.value) {
error.value = '请输入手机号'
;
isPhoneValid.value = false
;
return
;
error.value = '请输入手机号'
isPhoneValid.value = false
return
}
if (!/^1[3-9]\d{9}$/.test(mobile.value)) {
error.value = '请输入正确的手机号'
;
isPhoneValid.value = false
;
return
;
error.value = '请输入正确的手机号'
isPhoneValid.value = false
return
}
error.value = ''
;
isPhoneValid.value = true
;
}
;
error.value = ''
isPhoneValid.value = true
}
const startCountdown = () => {
countdown.value = 60
;
countdown.value = 60
const timer = setInterval(() => {
countdown.value--
;
countdown.value--
if (countdown.value <= 0) {
clearInterval(timer)
;
clearInterval(timer)
}
}, 1000)
;
}
;
}, 1000)
}
/**
* @description 点击微信图标触发微信授权登录
...
...
@@ -258,46 +267,50 @@ const startCountdown = () => {
const handleWxLoginClick = async () => {
// 非微信环境提示并不触发授权
if (!import.meta.env.DEV && !wxInfo().isWeiXin) {
showToast('请在微信内打开以完成微信授权登录');
return;
showToast('请在微信内打开以完成微信授权登录')
return
}
try {
// 手动发起微信授权流程(guards.js中实现)
await startWxAuth();
await startWxAuth()
} catch (e) {
console.error('微信授权触发失败:', e);
showToast('微信授权失败,请稍后重试');
console.error('微信授权触发失败:', e)
showToast('微信授权失败,请稍后重试')
}
}
;
}
const sendVerificationCode = async () => {
if (!isPhoneValid.value) {
return
;
return
}
try {
const { code } = await smsAPI({ mobile: mobile.value })
;
const { code } = await smsAPI({ mobile: mobile.value })
if (code === 1) {
showToast('验证码已发送')
;
startCountdown()
;
return
;
showToast('验证码已发送')
startCountdown()
return
}
} catch (err) {
console.error('Send verification code error:', err)
;
error.value = '发送验证码失败,请稍后重试'
;
console.error('Send verification code error:', err)
error.value = '发送验证码失败,请稍后重试'
}
}
;
}
const handleSubmit = async () => {
if (!mobile.value || (!isVerifyCodeLogin.value && !password.value) || (isVerifyCodeLogin.value && !verificationCode.value)) {
error.value = "请填写所有字段";
return;
if (
!mobile.value ||
(!isVerifyCodeLogin.value && !password.value) ||
(isVerifyCodeLogin.value && !verificationCode.value)
) {
error.value = '请填写所有字段'
return
}
try {
error.value =
"";
loading.value = true
;
error.value =
''
loading.value = true
// 调用登录接口
const response = await loginAPI({
...
...
@@ -305,38 +318,36 @@ const handleSubmit = async () => {
...(isVerifyCodeLogin.value
? { sms_code: verificationCode.value }
: { password: password.value }),
})
;
})
if (response.code !== 1) {
error.value = response.msg || "登录失败,请检查您的输入项";
return;
} else {
applyUserInfoAuth(response, { set_auth_headers: setAuthHeaders, storage: localStorage })
error.value = response.msg || '登录失败,请检查您的输入项'
return
}
applyUserInfoAuth(response, { set_auth_headers: setAuthHeaders, storage: localStorage })
const { code, data } = await getUserInfoAPI()
;
const { code, data } = await getUserInfoAPI()
if (code === 1) {
// 登录成功,更新auth状态,传递完整的用户信息包括打卡信息
const success = login({ ...data.user, ...data.checkin })
;
const success = login({ ...data.user, ...data.checkin })
if (success) {
// 如果有重定向参数,登录成功后跳转到对应页面
// 说明:redirect 是经过 URL 编码的,需要先解码再跳转
const redirect_raw = $route.query.redirect
;
const redirect = redirect_raw ? decodeURIComponent(redirect_raw) :
"/";
router.push(redirect)
;
const redirect_raw = $route.query.redirect
const redirect = redirect_raw ? decodeURIComponent(redirect_raw) :
'/'
router.push(redirect)
} else {
error.value =
"登录失败,请检查您的输入项";
error.value =
'登录失败,请检查您的输入项'
}
}
} catch (err) {
console.error(
"Login error:", err);
error.value =
"登录时发生错误";
console.error(
'Login error:', err)
error.value =
'登录时发生错误'
} finally {
loading.value = false
;
loading.value = false
}
}
;
}
// 说明:授权回跳的重定向处理已移动到路由层
</script>
...
...
Please
register
or
login
to post a comment