|
|
@@ -49,8 +49,55 @@
|
|
|
</view>
|
|
|
</template>
|
|
|
|
|
|
+ <template v-if="showSmsLogin">
|
|
|
+ <view class="login-form">
|
|
|
+ <view class="login-field">
|
|
|
+ <input
|
|
|
+ @focus="mobile=''"
|
|
|
+ v-model="mobile"
|
|
|
+ class="login-input"
|
|
|
+ placeholder="请输入手机号"
|
|
|
+ type="number"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <view class="login-field login-field--last" style="display: flex; align-items: center; justify-content: space-between;">
|
|
|
+ <view style="flex: 1; margin-right: 20upx;">
|
|
|
+ <input
|
|
|
+ @focus="smsCode=''"
|
|
|
+ v-model="smsCode"
|
|
|
+ class="login-input"
|
|
|
+ placeholder="请输入验证码"
|
|
|
+ type="number"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <button
|
|
|
+ class="admin-button-com middle blue"
|
|
|
+ :disabled="smsCountdown > 0"
|
|
|
+ @click="getSmsCode"
|
|
|
+ style="margin-top: 0; font-size: 26upx; height: 88upx; line-height: 88upx; padding: 0 20upx; min-width: 180upx; flex-shrink: 0; border-radius: 16upx;"
|
|
|
+ >
|
|
|
+ {{ smsCountdown > 0 ? smsCountdown + 's' : '获取验证码' }}
|
|
|
+ </button>
|
|
|
+ </view>
|
|
|
+ <button class="login-btn login-btn--primary" @click="smsLoginFun">登录</button>
|
|
|
+ </view>
|
|
|
+ <view class="login-agreement">
|
|
|
+ <checkbox-group @change="agreeItem">
|
|
|
+ <label class="login-agreement-label">
|
|
|
+ <checkbox value="1" class="login-checkbox" :checked="agree == 1" />
|
|
|
+ <text class="login-agreement-text">
|
|
|
+ 我已阅读并同意
|
|
|
+ <text class="login-agreement-link" @click.stop="goToService">《服务协议》</text>
|
|
|
+ 和
|
|
|
+ <text class="login-agreement-link" @click.stop="goToPrivacy">《隐私政策》</text>
|
|
|
+ </text>
|
|
|
+ </label>
|
|
|
+ </checkbox-group>
|
|
|
+ </view>
|
|
|
+ </template>
|
|
|
+
|
|
|
<!-- #ifdef MP-WEIXIN -->
|
|
|
- <view v-if="showAccountLogin == false" class="login-quick">
|
|
|
+ <view v-if="showAccountLogin == false && showSmsLogin == false" class="login-quick">
|
|
|
<view class="login-tip">
|
|
|
<text class="login-tip-line">这是花店管理后台,需获取你的手机号登录后</text>
|
|
|
<text class="login-tip-line">才能使用相应功能,请谅解</text>
|
|
|
@@ -68,7 +115,7 @@
|
|
|
<!-- #endif -->
|
|
|
|
|
|
<!-- #ifdef APP-PLUS -->
|
|
|
- <view v-if="showAccountLogin == false" class="login-quick">
|
|
|
+ <view v-if="showAccountLogin == false && showSmsLogin == false" class="login-quick">
|
|
|
<view class="login-tip">
|
|
|
<text class="login-tip-line">使用本机号码快速登录花掌柜</text>
|
|
|
</view>
|
|
|
@@ -90,16 +137,35 @@
|
|
|
<!-- #endif -->
|
|
|
|
|
|
<view class="login-footer-links">
|
|
|
+ <!-- 如果当前不是账号密码登录,显示切换到账号密码登录的链接 -->
|
|
|
<text
|
|
|
v-if="showAccountLogin == false"
|
|
|
class="login-footer-link"
|
|
|
@click="useAccount()"
|
|
|
>使用账号密码登录</text>
|
|
|
+ <!-- 如果当前是账号密码登录,显示切换到快捷登录的链接 -->
|
|
|
+ <text
|
|
|
+ v-else
|
|
|
+ class="login-footer-link"
|
|
|
+ @click="useMoibleAccount()"
|
|
|
+ >使用快捷登录</text>
|
|
|
+
|
|
|
+ <text class="login-footer-divider">|</text>
|
|
|
+
|
|
|
+ <!-- 如果当前不是短信登录,显示切换到短信登录的链接 -->
|
|
|
+ <text
|
|
|
+ v-if="showSmsLogin == false"
|
|
|
+ class="login-footer-link"
|
|
|
+ @click="useSms()"
|
|
|
+ >使用短信登录</text>
|
|
|
+ <!-- 如果当前是短信登录,显示切换到快捷登录的链接 -->
|
|
|
<text
|
|
|
v-else
|
|
|
class="login-footer-link"
|
|
|
@click="useMoibleAccount()"
|
|
|
- >使用手机号登录</text>
|
|
|
+ >使用快捷登录</text>
|
|
|
+
|
|
|
+ <text class="login-footer-divider">|</text>
|
|
|
<text class="login-footer-link login-footer-link--register" @click="register">注册账号</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
@@ -109,7 +175,7 @@
|
|
|
<script>
|
|
|
import { mapActions } from "vuex";
|
|
|
import { getShopInfo} from "@/utils/auth";
|
|
|
-import {appLogin} from '@/api/common'
|
|
|
+import {appLogin, sendLoginSms, smsLogin} from '@/api/common'
|
|
|
import { getDictionaries,postWxCode } from '@/api/mini'
|
|
|
import { phoneLogin,wxMobileLogin } from "@/api/auth";
|
|
|
import { ghsInfo } from "@/api/ghs/index";
|
|
|
@@ -122,11 +188,16 @@ export default {
|
|
|
password:'',
|
|
|
agree:0,
|
|
|
showAccountLogin:false,
|
|
|
+ showSmsLogin:false,
|
|
|
+ smsCode:'',
|
|
|
+ smsCountdown: 0,
|
|
|
+ smsTimer: null,
|
|
|
statusBarHeight: 0
|
|
|
};
|
|
|
},
|
|
|
onLoad(){
|
|
|
this.setStatusBarHeight();
|
|
|
+ this.initSmsCountdown();
|
|
|
let that = this
|
|
|
uni.getNetworkType({
|
|
|
success: function (res) {
|
|
|
@@ -161,6 +232,9 @@ export default {
|
|
|
},
|
|
|
onUnload(){
|
|
|
uni.offNetworkStatusChange(this.dealLogin)
|
|
|
+ if (this.smsTimer) {
|
|
|
+ clearInterval(this.smsTimer)
|
|
|
+ }
|
|
|
},
|
|
|
methods: {
|
|
|
...mapActions(['setUserShopAll']),
|
|
|
@@ -184,11 +258,19 @@ export default {
|
|
|
},
|
|
|
useMoibleAccount(){
|
|
|
this.showAccountLogin = false
|
|
|
+ this.showSmsLogin = false
|
|
|
this.agree = 0
|
|
|
this.$forceUpdate()
|
|
|
},
|
|
|
useAccount(){
|
|
|
this.showAccountLogin = true
|
|
|
+ this.showSmsLogin = false
|
|
|
+ this.agree = 0
|
|
|
+ this.$forceUpdate()
|
|
|
+ },
|
|
|
+ useSms(){
|
|
|
+ this.showAccountLogin = false
|
|
|
+ this.showSmsLogin = true
|
|
|
this.agree = 0
|
|
|
this.$forceUpdate()
|
|
|
},
|
|
|
@@ -490,6 +572,140 @@ export default {
|
|
|
})
|
|
|
})
|
|
|
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 【用途】初始化短信验证码倒计时
|
|
|
+ * 【为什么】在页面加载时检查本地缓存的上次验证码发送时间,若在60秒内,则恢复倒计时,防止刷新页面绕过倒计时限制
|
|
|
+ */
|
|
|
+ initSmsCountdown() {
|
|
|
+ let lastSentTime = uni.getStorageSync('last_sms_sent_time_login_hd')
|
|
|
+ if (lastSentTime) {
|
|
|
+ let timePassed = Math.floor((Date.now() - lastSentTime) / 1000)
|
|
|
+ if (timePassed < 60) {
|
|
|
+ this.startCountdown(60 - timePassed)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 【用途】启动短信倒计时定时器
|
|
|
+ * 【为什么】控制“获取验证码”按钮的禁用状态与倒计时秒数显示,防止频繁请求
|
|
|
+ * @param {Number} seconds 倒计时秒数
|
|
|
+ */
|
|
|
+ startCountdown(seconds) {
|
|
|
+ this.smsCountdown = seconds
|
|
|
+ if (this.smsTimer) {
|
|
|
+ clearInterval(this.smsTimer)
|
|
|
+ }
|
|
|
+ this.smsTimer = setInterval(() => {
|
|
|
+ this.smsCountdown--
|
|
|
+ if (this.smsCountdown <= 0) {
|
|
|
+ clearInterval(this.smsTimer)
|
|
|
+ this.smsTimer = null
|
|
|
+ }
|
|
|
+ }, 1000)
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 【用途】获取短信验证码的前置校验
|
|
|
+ * 【为什么】在发送验证码前校验手机号格式,确保输入有效,校验通过后触发发送逻辑
|
|
|
+ */
|
|
|
+ getSmsCode() {
|
|
|
+ let mobile = this.mobile
|
|
|
+ if (this.$util.isEmpty(mobile)) {
|
|
|
+ this.$msg('请输入手机号')
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ if (this.$util.checkMobile(mobile) == false) {
|
|
|
+ this.$msg('请输入正确手机号')
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ this.sendSms()
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 【用途】发送登录短信验证码
|
|
|
+ * 【为什么】调用后端发送短信接口,成功后记录发送时间戳并开启60秒倒计时
|
|
|
+ */
|
|
|
+ sendSms() {
|
|
|
+ let mobile = this.mobile
|
|
|
+ uni.showLoading({ mask: true })
|
|
|
+ sendLoginSms({
|
|
|
+ mobile: mobile
|
|
|
+ }).then(res => {
|
|
|
+ uni.hideLoading()
|
|
|
+ if (res.code == 1) {
|
|
|
+ this.$msg('验证码已发送')
|
|
|
+ uni.setStorageSync('last_sms_sent_time_login_hd', Date.now())
|
|
|
+ this.startCountdown(60)
|
|
|
+ }
|
|
|
+ }).catch(() => {
|
|
|
+ uni.hideLoading()
|
|
|
+ })
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 【用途】短信验证码登录提交逻辑
|
|
|
+ * 【为什么】校验手机号、验证码并确保用户同意服务协议后,调用后端 smsLogin 接口,登录成功后存储 Token 并初始化店铺数据
|
|
|
+ */
|
|
|
+ smsLoginFun() {
|
|
|
+ let that = this
|
|
|
+ let mobile = this.mobile
|
|
|
+ let code = this.smsCode
|
|
|
+ if (that.$util.isEmpty(mobile)) {
|
|
|
+ this.$msg('请输入手机号')
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ if (this.$util.checkMobile(mobile) == false) {
|
|
|
+ this.$msg('请输入正确手机号')
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ if (that.$util.isEmpty(code)) {
|
|
|
+ this.$msg('请输入验证码')
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查协议
|
|
|
+ this.checkAgreement(function() {
|
|
|
+ uni.showLoading({ mask: true })
|
|
|
+
|
|
|
+ smsLogin({ mobile, code, deviceId: uni.getStorageSync('deviceId') }).then(subRes => {
|
|
|
+ uni.hideLoading()
|
|
|
+
|
|
|
+ if (subRes.code == 1) {
|
|
|
+ if (that.$util.isEmpty(subRes)) {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+ uni.setStorageSync('token', subRes.data.token)
|
|
|
+ uni.setStorageSync('shopId', subRes.data.admin.currentShopId)
|
|
|
+ uni.setStorageSync('reachVip', subRes.data.reachVip)
|
|
|
+ that.$store.commit('setLoginInfo', { ...subRes.data.admin, ...subRes.data })
|
|
|
+ uni.removeStorageSync('manualLogout')
|
|
|
+
|
|
|
+ getDictionaries({ token: subRes.data.token }).then(res => {
|
|
|
+ if (that.$util.isEmpty(res)) {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ that.$store.commit('setDictionariesInfo', { ...res.data.dict, ...res.data })
|
|
|
+ that.$store.commit('setMyShopInfo', { ...res.data.shop, ...res.data })
|
|
|
+ })
|
|
|
+
|
|
|
+ getShopInfo(true).then(res => { uni.setNavigationBarTitle({ title: res.name }) })
|
|
|
+ that.setUserShopAll()
|
|
|
+ // #ifdef APP-PLUS
|
|
|
+ that.$util.afterAppLoginSuccess({ auto: 0 })
|
|
|
+ // #endif
|
|
|
+
|
|
|
+ //返回上一页带参数
|
|
|
+ let pages = getCurrentPages();
|
|
|
+ let prevPage = pages[ pages.length - 2 ];
|
|
|
+ if (prevPage && prevPage.$vm) {
|
|
|
+ prevPage.$vm.backAction = 'login'
|
|
|
+ uni.navigateBack()
|
|
|
+ } else {
|
|
|
+ // H5 直接访问登录页,没有上一页,回首页
|
|
|
+ uni.reLaunch({ url: '/admin/home/workbench' })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
@@ -673,7 +889,7 @@ export default {
|
|
|
display: flex;
|
|
|
flex-direction: row;
|
|
|
align-items: center;
|
|
|
- justify-content: space-between;
|
|
|
+ justify-content: center;
|
|
|
margin-top: 36upx;
|
|
|
padding-top: 28upx;
|
|
|
border-top: 1upx solid #f0f2f1;
|
|
|
@@ -685,6 +901,12 @@ export default {
|
|
|
line-height: 42upx;
|
|
|
}
|
|
|
|
|
|
+.login-footer-divider {
|
|
|
+ margin: 0 20upx;
|
|
|
+ color: #d8dee8;
|
|
|
+ font-size: 24upx;
|
|
|
+}
|
|
|
+
|
|
|
.login-footer-link--register {
|
|
|
color: #09c567;
|
|
|
font-weight: 600;
|