<template> <!-- 背景图容器 --> <view class="background-container"> <image class="background-image" src="/static/dlbj.jpg" mode="aspectFill" ></image> <!-- 半透明遮罩 --> <view class="overlay"></view> </view> <!-- 登录表单 --> <view class="login-container"> <view class="login-form"> <text class="login-title">用户登录</text> <input v-model="username" placeholder="用户名" class="login-input" placeholder-class="input-placeholder" /> <input v-model="password" type="password" placeholder="密码" class="login-input" placeholder-class="input-placeholder" /> <!-- 记住密码 --> <view class="remember-section"> <checkbox-group @change="toggleRemember"> <label class="checkbox-label"> <checkbox :checked="remember" color="#3498db" style="transform: scale(0.8);" /> <text>记住账号密码</text> </label> </checkbox-group> <text class="forgot-password" @click="handleForgotPassword">忘记账号密码</text> </view> <button class="login-button" :loading="loading" @click="handleLogin" >登录</button> </view> </view> </template> <script> import { ref,onMounted } from 'vue' import { onShow } from '@dcloudio/uni-app'; export default { setup() { const username = ref('') const password = ref('') const loading = ref(false) const remember = ref(false) // 记住密码状态 // 页面加载时检查是否有保存的凭据 onMounted(() => { const savedUsername = uni.getStorageSync('savedUsername') const savedPassword = uni.getStorageSync('savedPassword') if (savedUsername && savedPassword) { username.value = savedUsername password.value = savedPassword remember.value = true } }) // 切换记住密码状态 const toggleRemember = (e) => { remember.value = e.detail.value.length > 0 } // 忘记密码处理 const handleForgotPassword = () => { uni.showModal({ title: '忘记密码', content: '是否清除保存的账号密码?', success: (res) => { if (res.confirm) { // 清除保存的账号密码 uni.removeStorageSync('savedUsername') uni.removeStorageSync('savedPassword') username.value = '' password.value = '' remember.value = false uni.showToast({ title: '已清除账号密码', icon: 'success' }) } } }) } const handleLogin = async () => { // 验证输入 if (!username.value.trim()) { uni.showToast({ title: '请输入用户名', icon: 'none', duration: 2000 }) return } if (!password.value) { uni.showToast({ title: '请输入密码', icon: 'none', duration: 2000 }) return } loading.value = true try { // 兼容性请求 const response = await new Promise((resolve, reject) => { uni.request({ url: 'http://172.26.26.43/dev-api/login', method: 'POST', data: { username: username.value, password: password.value }, header: { 'Content-Type': 'application/json' }, timeout: 10000, success: (res) => resolve(res), fail: (err) => reject(err) }) }) // 处理响应 await handleResponse(response) // 登录成功后保存凭据(如果用户选择了记住密码) if (remember.value) { saveCredentials() } else { clearSavedCredentials() } } catch (error) { console.error('登录请求出错:', error) let errorMsg = '登录失败,请重试' if (error.errMsg) { errorMsg = `请求失败: ${error.errMsg}` } else if (error.message) { errorMsg = error.message } uni.showToast({ title: errorMsg, icon: 'none', duration: 2000 }) } finally { loading.value = false } } // 保存凭据到本地存储 const saveCredentials = () => { uni.setStorageSync('savedUsername', username.value) uni.setStorageSync('savedPassword', password.value) } // 清除保存的凭据 const clearSavedCredentials = () => { uni.removeStorageSync('savedUsername') uni.removeStorageSync('savedPassword') } // 清除token缓存 onShow(() => { uni.removeStorageSync('token'); uni.removeStorageSync('userInfo'); }); const handleResponse = async (response) => { // 检查HTTP状态码 if (response.statusCode < 200 || response.statusCode >= 300) { throw new Error(`服务器错误: ${response.statusCode}`) } // 解析响应数据 const { data } = response if (!data) { throw new Error('服务器返回空数据') } const { code, message, token } = data if (code === 200) { // 存储token uni.setStorageSync('token', token) uni.showToast({ title: '登录成功!', icon: 'success', duration: 1000 }) // 登录成功后跳转 setTimeout(() => { uni.redirectTo({ url: '/pages/index/index' }) }, 1000) } else { throw new Error(`登录失败: ${message || '未知错误'}`) } } // 在登录页面的onShow方法中 onShow(() => { // 清除 token 缓存 uni.removeStorageSync('token'); // 清除其他用户相关数据 uni.removeStorageSync('userInfo'); console.log('已清除登录状态缓存'); // 生产环境可移除 }); return { username, password, remember, loading, handleLogin, toggleRemember, handleForgotPassword } } } </script> <style scoped> /* 背景图容器 */ .background-container { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: -1; } /* 背景图片样式 */ .background-image { width: 100%; height: 100%; object-fit: cover; filter: brightness(0.7) blur(2rpx); } /* 半透明遮罩层 */ .overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient( to bottom, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0.4) 50%, rgba(0, 0, 0, 0.6) 100% ); } /* 登录容器 */ .login-container { display: flex; justify-content: center; align-items: center; min-height: 100vh; padding: 32rpx; } /* 登录表单 */ .login-form { width: 100%; max-width: 600rpx; padding: 60rpx; background: rgba(255, 255, 255, 0.9); border-radius: 24rpx; box-shadow: 0 8rpx 40rpx rgba(0, 0, 0, 0.2); backdrop-filter: blur(10rpx); animation: fadeInScale 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275); transform-origin: center; } /* 登录标题 */ .login-title { display: block; text-align: center; margin-bottom: 60rpx; font-size: 44rpx; font-weight: bold; color: #333; text-shadow: 0 1rpx 2rpx rgba(255, 255, 255, 0.8); letter-spacing: 1rpx; } /* 输入框样式 */ .login-input { width: 100%; height: 96rpx; padding: 0 30rpx; margin-bottom: 50rpx; border: 2rpx solid #ddd; border-radius: 16rpx; font-size: 34rpx; box-sizing: border-box; background: rgba(255, 255, 255, 0.95); box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05); transition: all 0.3s ease; } /* 输入框聚焦效果 */ .login-input:focus { border-color: #3498db; box-shadow: 0 0 0 4rpx rgba(52, 152, 219, 0.2); background: #fff; } .input-placeholder { color: #aaa; font-size: 34rpx; } /* 修改记住密码区域样式 */ .remember-section { display: flex; justify-content: space-between; /* 左右两端对齐 */ align-items: center; /* 垂直居中 */ margin-bottom: 30rpx; font-size: 28rpx; padding: 0 10rpx; /* 添加内边距 */ } .checkbox-label { display: flex; align-items: center; color: #555; flex-shrink: 0; /* 防止缩小 */ } .forgot-password { color: #e74c3c; /* 使用更醒目的颜色 */ text-decoration: underline; padding: 10rpx 0; flex-shrink: 0; /* 防止缩小 */ margin-left: 20rpx; /* 添加左边距 */ } /* 登录按钮 */ .login-button { width: 100%; height: 96rpx; line-height: 96rpx; background: linear-gradient(135deg, #3498db, #2980b9); color: white; font-size: 36rpx; font-weight: bold; border-radius: 16rpx; margin-top: 20rpx; border: none; box-shadow: 0 4rpx 15rpx rgba(41, 128, 185, 0.3); position: relative; overflow: hidden; transition: all 0.3s ease; } /* 按钮悬停效果 */ .login-button:hover { transform: translateY(-4rpx); box-shadow: 0 8rpx 20rpx rgba(41, 128, 185, 0.4); } /* 按钮点击效果 */ .login-button:active { transform: translateY(0); box-shadow: 0 2rpx 8rpx rgba(41, 128, 185, 0.3); } /* 按钮加载状态 */ .login-button[loading] { opacity: 0.8; } /* 按钮光晕效果 */ .login-button::after { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: radial-gradient(circle, rgba(255,255,255,0.4) 0%, transparent 70%); opacity: 0; transition: opacity 0.3s ease; } .login-button:hover::after { opacity: 1; } /* 表单动画 */ @keyframes fadeInScale { from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); } } /* 响应式调整 */ @media (max-width: 480px) { .login-form { padding: 40rpx; max-width: 90%; } .login-title { font-size: 40rpx; margin-bottom: 50rpx; } .login-input { height: 88rpx; font-size: 32rpx; } .login-button { height: 88rpx; line-height: 88rpx; } } </style>
我点击登录后浏览器控制台报错:uni-h5.es.js:2712
Uncaught (in promise)
{errMsg: ‘redirectTo:fail can not redirectTo a tabbar page’}
errMsg
:
“redirectTo:fail can not redirectTo a tabbar page”
[[Prototype]]
:
Object
我的package.json代码如下:{
“easycom”: {
“autoscan”: true,
“custom”: {
“^u-(.)": “uview-plus/components/u-$1/u-$1.vue”,
"uni-(.)”: “@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue”
}
},
“pages”: [
{
“path”: “pages/guide/guide”,
“style”: {
// “navigationBarTitleText”: “引导页”
}
},
{
“path”: “pages/index/index”,
“style”: {
// “navigationBarTitleText”: “首页”
}
},
{
“path”: “pages/login/login”,
“style”: {
“navigationBarTitleText”: “登录”
}
},
{
“path”: “pages/message/message”,
“style”: {
“navigationBarTitleText”: “消息”,
“enablePullDownRefresh”: true
}
},
{
“path”: “pages/workbench/workbench”,
“style”: {
“navigationBarTitleText”: “工作台”,
“enablePullDownRefresh”: true
}
},
{
“path”: “pages/workbench/mycp/detail/detail”,
“style”: {
// “navigationBarTitleText”: “民意测评的详情页”
}
},
{
“path”: “pages/workbench/mycp/operation/operation”,
“style”: {
// “navigationBarTitleText”: “民意测评的操作页”
}
},
{
“path”: “pages/my/my”,
“style”: {
“navigationBarTitleText”: “我的”
}
}
],
“tabBar”: {
“color”: “#7A7E83”, // 未选中颜色
“selectedColor”: “#007AFF”, // 选中颜色
“borderStyle”: “white”, // 边框颜色
“backgroundColor”: “#FFFFFF”, // 背景色
“list”: [
{
“pagePath”: “pages/message/message”,
“iconPath”: “static/tabbar/message.png”,
“selectedIconPath”: “static/tabbar/message-active.png”,
“text”: “消息”
},
{
“pagePath”: “pages/workbench/mycp/detail/detail”,
“iconPath”: “static/tabbar/workbench.png”,
“selectedIconPath”: “static/tabbar/workbench-active.png”,
“text”: “工作台”
},
{
“pagePath”: “pages/index/index”,
“iconPath”: “static/tabbar/profile.png”,
“selectedIconPath”: “static/tabbar/profile-active.png”,
“text”: “首页”
},
{
“pagePath”: “pages/my/my”,
“iconPath”: “static/tabbar/profile.png”,
“selectedIconPath”: “static/tabbar/profile-active.png”,
“text”: “我的”
}
]
},
“globalStyle”: {
“navigationBarTextStyle”: “black”,
“navigationBarTitleText”: “工具系统”,
“navigationBarBackgroundColor”: “#F8F8F8”,
“backgroundColor”: “#F8F8F8”
},
“uniIdRouter”: {}
}