Files
Market_Uniapp/src/pages/login/login.vue
2025-08-07 11:07:18 +08:00

576 lines
12 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="login-container">
<!-- 语言选择文字按钮点击文字即可弹出窗口 -->
<view class="language-text-btn" @click="showLanguageModal = true">
<text class="lang-text">{{ $t('login.changelanguage') }}</text>
<i class="iconfont icon-arrow-down"></i>
</view>
<!-- 语言选择弹窗 -->
<view class="lang-modal" v-if="showLanguageModal">
<view class="modal-mask" @click="showLanguageModal = false"></view>
<view class="modal-content">
<view class="modal-title">{{ $t('login.chooseLanguage') }}</view>
<view class="lang-list">
<view
class="lang-item"
@click="changeLanguage('en')"
:class="{ 'active': currentLang === 'en' }"
>
<text>English</text>
<i class="iconfont icon-check" v-if="currentLang === 'en'"></i>
</view>
<view
class="lang-item"
@click="changeLanguage('zh')"
:class="{ 'active': currentLang === 'zh' }"
>
<text>Chinese</text>
<i class="iconfont icon-check" v-if="currentLang === 'zh'"></i>
</view>
</view>
<button class="modal-close" @click="showLanguageModal = false">
{{ $t('login.languagechangeclose') }}
</button>
</view>
</view>
<!-- 顶部标题 -->
<view class="login-header">
<text class="app-title">{{ $t('login.appTitle') }}</text>
</view>
<!-- 登录表单 -->
<view class="login-form">
<!-- 账号输入 -->
<view class="form-group">
<text class="input-label">{{ $t('login.idCardLabel') }}</text>
<view class="input-wrapper">
<i class="iconfont icon-user"></i>
<input
type="text"
v-model="username"
:placeholder="$t('login.usernamePlaceholder')"
class="input-field"
maxlength="6"
/>
</view>
</view>
<!-- 密码输入 -->
<view class="form-group">
<text class="input-label">{{ $t('login.passwordLabel') }}</text>
<view class="input-wrapper">
<i class="iconfont icon-lock"></i>
<input
:type="showPassword ? 'text' : 'password'"
v-model="password"
:placeholder="$t('login.passwordPlaceholder')"
class="input-field"
/>
<button
class="toggle-btn"
@click.stop="togglePasswordVisibility"
:class="{ active: showPassword }"
>
<i class="iconfont" :class="showPassword ? 'icon-eye' : 'icon-eye-close'"></i>
</button>
</view>
</view>
<!-- 记住密码选项 -->
<view class="remember-section">
<view class="remember-check">
<checkbox
v-model="rememberPassword"
class="remember-checkbox"
color="#007aff"
/>
<text class="remember-text">{{ $t('login.rememberPassword') }}</text>
</view>
<!-- <text class="forgot-link" @click="handleForgotPassword">
{{ $t('login.forgotPassword') }}
</text> -->
</view>
<!-- 错误提示 -->
<view class="error-message" v-if="showError">
{{ errorMessage }}
</view>
<!-- 登录按钮 -->
<!-- <button
class="login-btn"
@click="handleLogin"
:disabled="isLoading || !agreeTerms"
>
<template v-if="isLoading">
<i class="iconfont icon-loading loading-icon"></i>
</template>
{{ $t('login.loginButton') }}
</button> -->
<button
class="login-btn"
@click="handleLogin"
>
<template v-if="isLoading">
<i class="iconfont icon-loading loading-icon"></i>
</template>
{{ $t('login.loginButton') }}
</button>
<!-- 协议同意勾选框 -->
<view class="agreement-check">
<checkbox
v-model="agreeTerms"
class="agree-checkbox"
color="#007aff"
/>
<text class="agree-text">
{{ $t('login.agreeTermsPrefix') }}
<text class="link" @click="openAgreement('terms')">{{ $t('login.userAgreement') }}</text>
{{ $t('login.and') }}
<text class="link" @click="openAgreement('privacy')">{{ $t('login.privacyPolicy') }}</text>
</text>
</view>
<!-- 注册链接 -->
<view class="register-link-section">
<text class="register-text">
{{ $t('login.noAccount') }}
<text class="register-link" @click="navigateToRegister">
{{ $t('login.registerButton') }}
</text>
</text>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
username: '',
password: '',
showError: false,
errorMessage: '',
isLoading: false,
currentLang: 'en', // 默认英文
agreeTerms: false,
rememberPassword: false,
showLanguageModal: false,
showPassword: false
}
},
onLoad() {
this.currentLang = this.$i18n.locale
this.loadRememberedAccount()
},
methods: {
togglePasswordVisibility() {
this.showPassword = !this.showPassword
},
loadRememberedAccount() {
const remembered = uni.getStorageSync('rememberedAccount')
if (remembered && remembered.expire > Date.now()) {
this.username = remembered.username
this.password = remembered.password
this.rememberPassword = true
}
},
saveRememberedAccount() {
if (this.rememberPassword) {
const expire = Date.now() + 30 * 24 * 60 * 60 * 1000
uni.setStorageSync('rememberedAccount', {
username: this.username,
password: this.password,
expire
})
} else {
uni.removeStorageSync('rememberedAccount')
}
},
changeLanguage(lang) {
this.currentLang = lang
this.$i18n.locale = lang
this.showError = false
this.showLanguageModal = false
},
handleLogin() {
// if (!this.agreeTerms) {
// this.showError = true
// this.errorMessage = this.$t('login.errors.agreeTermsFirst')
// return
// }
if (!this.username) {
this.showError = true
this.errorMessage = this.$t('login.errors.emptyUsername')
return
}
if (this.username.length !== 6 || !/^\d{6}$/.test(this.username)) {
this.showError = true
this.errorMessage = this.$t('login.errors.invalidIdCard')
return
}
if (!this.password) {
this.showError = true
this.errorMessage = this.$t('login.errors.emptyPassword')
return
}
this.isLoading = true
this.showError = false
// 模拟登录过程
setTimeout(() => {
console.log('登录信息:', { username: this.username, password: this.password })
this.saveRememberedAccount()
this.isLoading = false
// 确保只跳转一次
uni.reLaunch({
url: '/pages/home/index',
success: () => {
console.log('跳转成功')
},
fail: (err) => {
console.error('跳转失败:', err)
}
})
}, 1500)
},
navigateToRegister() {
uni.navigateTo({ url: '/pages/register/register' })
},
openAgreement(type) {
const title = type === 'terms'
? this.$t('login.userAgreement')
: this.$t('login.privacyPolicy')
uni.showModal({
title,
content: this.$t(`login.${type}Content`),
showCancel: false,
confirmText: this.$t('login.confirm')
})
},
//修改密码的js实现方法
// handleForgotPassword() {
// uni.showModal({
// title: this.$t('login.forgotPassword'),
// content: this.$t('login.forgotPasswordDesc'),
// confirmText: this.$t('login.resetPassword'),
// success: (res) => {
// if (res.confirm) {
// uni.navigateTo({ url: '/pages/reset-password/reset-password' })
// }
// }
// })
// }
}
}
</script>
<style scoped>
.login-container {
display: flex;
flex-direction: column;
min-height: 100vh;
padding: 0 30rpx;
background-color: #f5f5f5;
position: relative;
}
/* 语言选择文字按钮样式(核心修改) */
.language-text-btn {
position: absolute;
top: 30rpx;
right: 30rpx;
z-index: 10;
display: flex;
align-items: center;
padding: 10rpx 20rpx;
color: #007aff; /* 使用主题色突出显示 */
font-size: 28rpx;
cursor: pointer; /* 显示指针光标表明可点击 */
}
/* 保持下拉箭头样式 */
.icon-arrow-down {
font-size: 24rpx;
margin-left: 8rpx;
}
/* 语言弹窗样式保持不变 */
.lang-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 999;
}
.modal-mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
}
.modal-content {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background-color: #fff;
border-radius: 30rpx 30rpx 0 0;
padding: 30rpx;
}
.modal-title {
text-align: center;
font-size: 34rpx;
font-weight: bold;
color: #333;
padding: 20rpx 0;
border-bottom: 1px solid #eee;
margin-bottom: 20rpx;
}
.lang-list {
margin-bottom: 30rpx;
}
.lang-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 25rpx 10rpx;
font-size: 30rpx;
border-bottom: 1px solid #f1f1f1;
}
.lang-item.active {
color: #007aff;
}
.icon-check {
font-size: 32rpx;
}
.modal-close {
width: 100%;
height: 90rpx;
line-height: 90rpx;
background-color: #007aff;
color: #fff;
font-size: 32rpx;
border-radius: 45rpx;
}
/* 其他样式保持不变 */
.login-header {
padding-top: 160rpx;
padding-bottom: 100rpx;
text-align: center;
}
.app-title {
font-size: 60rpx;
font-weight: bold;
color: #333;
display: block;
margin-top: 60rpx;
margin-bottom: 40rpx;
}
.login-form {
flex: 1;
}
.form-group {
margin-bottom: 30rpx;
}
.input-label {
display: block;
font-size: 26rpx;
color: #000000;
margin-bottom: 15rpx;
padding-left: 30rpx;
}
.input-wrapper {
display: flex;
align-items: center;
background-color: #fff;
border-radius: 80rpx;
padding: 0 30rpx;
height: 90rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
}
.iconfont {
font-size: 36rpx;
color: #999;
margin-right: 20rpx;
}
.input-field {
flex: 1;
height: 100%;
font-size: 30rpx;
color: #333;
}
.input-field::placeholder {
color: #ccc;
}
.toggle-btn {
width: 50rpx;
height: 50rpx;
display: flex;
align-items: center;
justify-content: center;
background: transparent;
padding: 0;
margin: 0;
border: none;
}
.toggle-btn .iconfont {
margin: 0;
color: #999;
font-size: 34rpx;
}
.toggle-btn.active .iconfont {
color: #007aff;
}
.remember-section {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 30rpx;
margin-bottom: 10rpx;
}
.remember-check {
display: flex;
align-items: center;
}
.remember-checkbox {
transform: scale(0.8);
margin-right: 15rpx;
}
.remember-text {
font-size: 26rpx;
color: #666;
}
.forgot-link {
font-size: 26rpx;
color: #007aff;
}
.error-message {
color: #ff4d4f;
font-size: 26rpx;
padding: 15rpx 30rpx;
height: 60rpx;
}
.agreement-check {
display: flex;
align-items: center;
padding: 20rpx 30rpx;
margin-bottom: 10rpx;
}
.agree-checkbox {
transform: scale(0.8);
margin-right: 15rpx;
}
.agree-text {
font-size: 24rpx;
color: #666;
line-height: 1.4;
}
.link {
color: #007aff;
text-decoration: underline;
}
.login-btn {
width: 100%;
height: 90rpx;
line-height: 90rpx;
border-radius: 80rpx;
background-color: #007aff !important;
color: #ffffff !important;
font-size: 32rpx;
font-weight: 500;
margin-top: 20rpx;
display: flex;
align-items: center;
justify-content: center;
border: none;
padding: 0;
}
.login-btn:disabled {
background-color: #b3d4fc !important;
color: #ffffff !important;
}
.register-link-section {
text-align: center;
margin-top: 30rpx;
margin-bottom: 50rpx;
}
.register-text {
font-size: 28rpx;
color: #666;
}
.register-link {
color: #007aff;
margin-left: 5rpx;
text-decoration: underline;
}
.loading-icon {
animation: spin 1s linear infinite;
margin-right: 10rpx;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
</style>