|
|
@@ -8,10 +8,28 @@
|
|
|
</view>
|
|
|
|
|
|
<view class="form">
|
|
|
- <input class="input" v-model="mobile" placeholder="手机号" type="number" />
|
|
|
+ <view class="input-row">
|
|
|
+ <input
|
|
|
+ class="input input-grow"
|
|
|
+ v-model="mobile"
|
|
|
+ placeholder="手机号"
|
|
|
+ type="number"
|
|
|
+ @focus="onMobileFocus"
|
|
|
+ />
|
|
|
+ <view class="history-btn" @click="showAccountHistory">
|
|
|
+ <text>历史</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
|
|
|
<input v-if="loginType === 'password'" class="input" v-model="password" placeholder="密码" password />
|
|
|
|
|
|
+ <view v-if="loginType === 'password'" class="remember-row" @click="rememberPassword = !rememberPassword">
|
|
|
+ <view class="remember-box" :class="{ on: rememberPassword }">
|
|
|
+ <text v-if="rememberPassword" class="remember-tick">✓</text>
|
|
|
+ </view>
|
|
|
+ <text class="remember-label">记住密码</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
<view v-else class="sms-row">
|
|
|
<input class="input sms-input" v-model="code" placeholder="验证码" type="number" />
|
|
|
<view class="sms-btn" :class="{ disabled: sending || countdown > 0 }" @click="onSendCode">
|
|
|
@@ -30,6 +48,25 @@
|
|
|
import { login, loginBySms, sendSmsCode, setToken, getCurrentUserInfo, getUserIdFromToken } from '../../utils/api'
|
|
|
|
|
|
const USER_KEY = 'current_user'
|
|
|
+ const LOGIN_ACCOUNTS_KEY = 'login_saved_accounts'
|
|
|
+ const REMEMBER_PREF_KEY = 'login_remember_password_pref'
|
|
|
+
|
|
|
+ function loadSavedAccounts() {
|
|
|
+ try {
|
|
|
+ const raw = uni.getStorageSync(LOGIN_ACCOUNTS_KEY)
|
|
|
+ if (raw == null || raw === '') return []
|
|
|
+ const arr = typeof raw === 'string' ? JSON.parse(raw) : raw
|
|
|
+ return Array.isArray(arr) ? arr : []
|
|
|
+ } catch (e) {
|
|
|
+ return []
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function saveAccounts(list) {
|
|
|
+ try {
|
|
|
+ uni.setStorageSync(LOGIN_ACCOUNTS_KEY, JSON.stringify(list))
|
|
|
+ } catch (e) {}
|
|
|
+ }
|
|
|
|
|
|
export default {
|
|
|
data() {
|
|
|
@@ -38,10 +75,23 @@
|
|
|
mobile: '',
|
|
|
password: '',
|
|
|
code: '',
|
|
|
+ rememberPassword: false,
|
|
|
loading: false,
|
|
|
sending: false,
|
|
|
countdown: 0,
|
|
|
- timer: null
|
|
|
+ timer: null,
|
|
|
+ _historyShownForFocus: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onLoad() {
|
|
|
+ try {
|
|
|
+ const pref = uni.getStorageSync(REMEMBER_PREF_KEY)
|
|
|
+ if (pref === true || pref === 'true') this.rememberPassword = true
|
|
|
+ } catch (e) {}
|
|
|
+ const list = loadSavedAccounts()
|
|
|
+ if (list.length && list[0].mobile) {
|
|
|
+ this.mobile = list[0].mobile
|
|
|
+ if (this.rememberPassword && list[0].password) this.password = list[0].password
|
|
|
}
|
|
|
},
|
|
|
onUnload() {
|
|
|
@@ -49,6 +99,56 @@
|
|
|
this.timer = null
|
|
|
},
|
|
|
methods: {
|
|
|
+ onMobileFocus() {
|
|
|
+ const list = loadSavedAccounts()
|
|
|
+ if (!list.length || this._historyShownForFocus) return
|
|
|
+ this._historyShownForFocus = true
|
|
|
+ this.showAccountHistory()
|
|
|
+ },
|
|
|
+
|
|
|
+ showAccountHistory() {
|
|
|
+ const accounts = loadSavedAccounts()
|
|
|
+ if (!accounts.length) {
|
|
|
+ uni.showToast({ title: '暂无历史账号', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const itemList = accounts.map((a) => String(a.mobile || ''))
|
|
|
+ uni.showActionSheet({
|
|
|
+ itemList,
|
|
|
+ success: (res) => {
|
|
|
+ const acc = accounts[res.tapIndex]
|
|
|
+ if (!acc || !acc.mobile) return
|
|
|
+ this.mobile = String(acc.mobile)
|
|
|
+ if (this.loginType === 'password' && acc.password) {
|
|
|
+ this.password = acc.password
|
|
|
+ this.$nextTick(() => this.onLogin())
|
|
|
+ } else {
|
|
|
+ this.password = ''
|
|
|
+ }
|
|
|
+ },
|
|
|
+ fail: () => {}
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ recordSuccessfulLogin() {
|
|
|
+ const m = String(this.mobile || '').trim()
|
|
|
+ if (!m) return
|
|
|
+ const prevList = loadSavedAccounts()
|
|
|
+ const prev = prevList.find((a) => a.mobile === m)
|
|
|
+ const rest = prevList.filter((a) => a.mobile !== m)
|
|
|
+ const item = { mobile: m }
|
|
|
+ if (this.loginType === 'password') {
|
|
|
+ if (this.rememberPassword) item.password = this.password
|
|
|
+ } else if (prev && prev.password) {
|
|
|
+ item.password = prev.password
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ uni.setStorageSync(REMEMBER_PREF_KEY, !!this.rememberPassword)
|
|
|
+ } catch (e) {}
|
|
|
+ rest.unshift(item)
|
|
|
+ saveAccounts(rest.slice(0, 30))
|
|
|
+ },
|
|
|
+
|
|
|
async onSendCode() {
|
|
|
if (this.sending || this.countdown > 0) return
|
|
|
if (!this.mobile) {
|
|
|
@@ -122,6 +222,8 @@
|
|
|
uni.setStorageSync(USER_KEY, user || {})
|
|
|
} catch (e) {}
|
|
|
|
|
|
+ this.recordSuccessfulLogin()
|
|
|
+
|
|
|
uni.reLaunch({ url: '/pages/index/index' })
|
|
|
} catch (e) {
|
|
|
uni.showToast({ title: e.message || '登录失败', icon: 'none' })
|
|
|
@@ -165,6 +267,28 @@
|
|
|
.form {
|
|
|
margin-top: 24rpx;
|
|
|
}
|
|
|
+ .input-row {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 16rpx;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+ }
|
|
|
+ .input-grow {
|
|
|
+ flex: 1;
|
|
|
+ margin-bottom: 0;
|
|
|
+ }
|
|
|
+ .history-btn {
|
|
|
+ height: 88rpx;
|
|
|
+ padding: 0 28rpx;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ background: #f0f0f0;
|
|
|
+ color: #259653;
|
|
|
+ font-size: 26rpx;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ flex-shrink: 0;
|
|
|
+ }
|
|
|
.input {
|
|
|
height: 88rpx;
|
|
|
padding: 0 24rpx;
|
|
|
@@ -173,6 +297,36 @@
|
|
|
font-size: 28rpx;
|
|
|
margin-bottom: 20rpx;
|
|
|
}
|
|
|
+ .remember-row {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 16rpx;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+ margin-top: -8rpx;
|
|
|
+ }
|
|
|
+ .remember-box {
|
|
|
+ width: 36rpx;
|
|
|
+ height: 36rpx;
|
|
|
+ border-radius: 8rpx;
|
|
|
+ border: 2rpx solid #ccc;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+ .remember-box.on {
|
|
|
+ background: #259653;
|
|
|
+ border-color: #259653;
|
|
|
+ }
|
|
|
+ .remember-tick {
|
|
|
+ color: #fff;
|
|
|
+ font-size: 22rpx;
|
|
|
+ line-height: 1;
|
|
|
+ }
|
|
|
+ .remember-label {
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #666;
|
|
|
+ }
|
|
|
.sms-row {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
@@ -211,4 +365,3 @@
|
|
|
opacity: 0.7;
|
|
|
}
|
|
|
</style>
|
|
|
-
|