Files
smartDriveEEUniApp/uni_modules/uni-id-pages/pages/login/login-withpwd.vue
2026-04-18 07:52:47 +08:00

315 lines
9.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- 账号密码登录页 -->
<template>
<view class="uni-content">
<view class="login-logo">
<image :src="logo"></image>
</view>
<!-- 顶部文字 -->
<text class="title title-box">账号密码登录</text>
<uni-forms>
<uni-forms-item name="username">
<uni-easyinput :focus="focusUsername" @blur="focusUsername = false" class="input-box"
:inputBorder="false" v-model="username" placeholder="请输入手机号/用户名/邮箱" trim="all" />
</uni-forms-item>
<uni-forms-item name="password">
<uni-easyinput :focus="focusPassword" @blur="focusPassword = false" class="input-box" clearable
type="password" :inputBorder="false" v-model="password" placeholder="请输入密码" trim="all" />
</uni-forms-item>
</uni-forms>
<uni-captcha v-if="needCaptcha" focus ref="captcha" scene="login-by-pwd" v-model="captcha" />
<!-- 带选择框的隐私政策协议组件 -->
<uni-id-pages-agreements scope="login" ref="agreements"></uni-id-pages-agreements>
<button class="uni-btn" type="primary" @click="pwdLogin">登录</button>
<!-- 忘记密码 -->
<view class="link-box">
<view v-if="!config.isAdmin">
<text class="forget">忘记了</text>
<text class="link" @click="toRetrievePwd">找回密码</text>
</view>
<text class="link" @click="toRegister">{{config.isAdmin ? '注册管理员账号': '注册账号'}}</text>
<!-- <text class="link" @click="toRegister" v-if="!config.isAdmin">注册账号</text> -->
</view>
<!-- 悬浮登录方式组件 -->
<uni-id-pages-fab-login ref="uniFabLogin"></uni-id-pages-fab-login>
</view>
</template>
<script>
import mixin from '@/uni_modules/uni-id-pages/common/login-page.mixin.js';
import { store, mutations } from '@/common/store.js'
import { getApiUrl } from '@/common/config.js'
export default {
mixins: [mixin],
data() {
return {
// 默认账号密码(仅用于开发调试,发布前请移除或置空)
"password": "aaa123",
"username": "15810181776",
"captcha": "",
"needCaptcha": false,
"focusUsername": false,
"focusPassword": false,
"logo": "/static/logo.png"
}
},
onShow() {
// #ifdef H5
document.onkeydown = event => {
var e = event || window.event;
if (e && e.keyCode == 13) { //回车键的键值为13
this.pwdLogin()
}
};
// #endif
},
methods: {
// 页面跳转,找回密码
toRetrievePwd() {
let url = '/uni_modules/uni-id-pages/pages/retrieve/retrieve'
//如果刚好用户名输入框的值为手机号码就把它传到retrieve页面根据该手机号找回密码
if (/^1\d{10}$/.test(this.username)) {
url += `?phoneNumber=${this.username}`
}
uni.navigateTo({
url
})
},
/**
* 密码登录(调用后端 /api/sys/auth/login 接口)
*/
async pwdLogin() {
if (!this.password.length) {
this.focusPassword = true
return uni.showToast({
title: '请输入密码',
icon: 'none',
duration: 3000
});
}
if (!this.username.length) {
this.focusUsername = true
return uni.showToast({
title: '请输入手机号/用户名/邮箱',
icon: 'none',
duration: 3000
});
}
if (this.needAgreements && !this.agree) {
return this.$refs.agreements.popup(this.pwdLogin)
}
// 组装后端登录参数
const payload = {
userName: this.username,
password: this.password
}
uni.showLoading({
title: '正在登录...',
mask: true
})
try {
// 使用 uni.request 直接调用登录接口(登录接口不需要 token
const loginUrl = getApiUrl('/api/sys/auth/login')
console.log('[Login Page] 开始调用登录接口:', {
url: loginUrl,
method: 'POST',
payload: payload
})
const res = await new Promise((resolve, reject) => {
console.log('[Login Page] 发起 uni.request 调用')
uni.request({
url: loginUrl,
method: 'POST',
header: {
'Content-Type': 'application/json'
},
data: payload,
success: (res) => {
console.log('[Login Page] 登录请求成功:', {
statusCode: res.statusCode,
hasData: !!res.data,
dataType: typeof res.data
})
resolve(res)
},
fail: (err) => {
console.error('[Login Page] 登录请求失败:', {
error: err,
errorMessage: err.errMsg || '未知错误'
})
reject(err)
}
})
})
const body = res.data || {}
if (!body.success || !body.data) {
return uni.showToast({
title: body.message || '登录失败',
icon: 'none',
duration: 3000
})
}
const loginData = body.data
console.log('[Login Success] current user role info:', {
roleName: loginData.roleName || '',
scenario: loginData.scenario || ''
})
// 保存 token重要后续所有请求会自动在 header 中携带此 token
if (loginData.token) {
uni.setStorageSync('backend-token', loginData.token)
console.log('[Login] token 已保存,后续请求将自动在 header 中携带')
} else {
console.warn('[Login] 登录响应中未包含 token')
}
// 持久化其他登录信息
try {
uni.setStorageSync('backend-login-response', loginData)
uni.setStorageSync('backend-user-id', loginData.userId)
// 保存 tenantId后续所有请求会自动在 X-Tenant-Id header 中携带)
if (loginData.tenantId) {
uni.setStorageSync('backend-tenant-id', loginData.tenantId)
console.log('[Login] tenantId 已保存:', loginData.tenantId)
} else {
console.warn('[Login] 登录响应中未包含 tenantId后续请求可能失败')
}
// 保存 roleName 和 scenario后续所有请求会自动在 header 中携带
if (loginData.roleName) {
uni.setStorageSync('backend-role-name', loginData.roleName)
console.log('[Login] roleName 已保存:', loginData.roleName)
}
if (loginData.scenario) {
uni.setStorageSync('backend-scenario', loginData.scenario)
console.log('[Login] scenario 已保存:', loginData.scenario)
}
} catch (e) {
console.error('缓存登录信息失败:', e)
}
// 通知自定义 TabBar 更新角色可见性(隐藏/显示“教务”)
try {
uni.$emit('tabbar:refresh')
} catch (e) {
console.warn('触发 tabbar 刷新事件失败:', e)
}
// 同步更新前端 store保证"我的"页等能识别为已登录状态
try {
const avatarStr = loginData.avatar != null && loginData.avatar !== ''
? String(loginData.avatar).trim()
: ''
mutations.setUserInfo({
username: loginData.userName,
mobile: loginData.phone,
email: loginData.email,
avatar_file: avatarStr ? { url: avatarStr } : undefined
}, { cover: true })
console.log('[Login] Store updated successfully, hasLogin:', store.hasLogin, 'userInfo:', store.userInfo)
} catch (e) {
console.error('更新本地用户信息失败:', e)
}
uni.showToast({
title: body.message || '登录成功',
icon: 'none',
duration: 800
})
// 更新全局角色信息
try {
const app = getApp({ allowDefault: true });
if (app && app.setGlobalRoleInfo) {
app.setGlobalRoleInfo();
}
} catch (e) {
console.warn('[Login] Failed to update global role info:', e);
}
// 登录成功后跳转到首页tabBar 首页:工作台)
// 在微信小程序中增加延迟确保store更新完全后再跳转
// #ifdef MP-WEIXIN
setTimeout(() => {
console.log('[Login] Preparing to navigate after login, hasLogin:', store.hasLogin)
uni.switchTab({
url: '/pages/workbench/workbench',
success: () => {
console.log('[Login] Navigation successful, checking login status after navigation')
// 延迟检查,确保页面跳转完成后再检查状态
setTimeout(() => {
console.log('[Login] Final check - hasLogin:', store.hasLogin, 'backend-token exists:', !!uni.getStorageSync('backend-token'))
}, 500)
},
fail: (err) => {
console.error('[Login] Navigation failed:', err)
}
})
}, 500)
// #endif
// #ifndef MP-WEIXIN
setTimeout(() => {
uni.switchTab({
url: '/pages/workbench/workbench'
})
}, 300)
// #endif
} catch (err) {
console.error('调用登录接口失败:', err)
uni.showToast({
title: '网络异常,登录失败',
icon: 'none',
duration: 3000
})
} finally {
uni.hideLoading()
}
},
/* 前往注册 */
toRegister() {
uni.navigateTo({
url: this.config.isAdmin ? '/uni_modules/uni-id-pages/pages/register/register-admin' :
'/uni_modules/uni-id-pages/pages/register/register',
fail(e) {
console.error(e);
}
})
}
}
}
</script>
<style lang="scss" scoped>
@import "@/uni_modules/uni-id-pages/common/login-page.scss";
@media screen and (min-width: 690px) {
.uni-content {
height: auto;
}
}
.forget {
font-size: 12px;
color: #8a8f8b;
}
.link-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: space-between;
margin-top: 20px;
}
.link {
font-size: 12px;
}
</style>