|
|
@@ -0,0 +1,319 @@
|
|
|
+<!-- pages/mine/login.vue -->
|
|
|
+<template>
|
|
|
+ <view class="login-page">
|
|
|
+ <!-- 标题图片占位区 -->
|
|
|
+ <view class="logo-placeholder">
|
|
|
+ <image src="/static/img/logo.png"></image>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 账号密码登录区域(根据模式显示) -->
|
|
|
+ <template v-if="loginMode === 'password'">
|
|
|
+ <!-- 手机号输入框 -->
|
|
|
+ <view class="input-wrapper">
|
|
|
+ <input v-model="phone" type="number" maxlength="11" class="input-field" placeholder="请输入帐号"
|
|
|
+ placeholder-style="color: #999;" confirm-type="done" />
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 密码输入框 -->
|
|
|
+ <view class="input-wrapper">
|
|
|
+ <input v-model="password" :password="true" maxlength="20" class="input-field" placeholder="请输入密码"
|
|
|
+ placeholder-style="color: #999;" confirm-type="done" />
|
|
|
+ </view>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <!-- 协议同意行 -->
|
|
|
+ <view class="agreement-row">
|
|
|
+ <checkbox-group @change="onAgreeChange">
|
|
|
+ <checkbox :value="'agree'" :checked="agree" class="agree-checkbox" color="#007AFF">
|
|
|
+ 我已阅读并同意
|
|
|
+ </checkbox>
|
|
|
+ </checkbox-group>
|
|
|
+ <text class="agree-text"></text>
|
|
|
+ <text class="link-text" @click.stop="toUserAgreement">《用户协议》</text>
|
|
|
+ <text class="link-text" @click.stop="toPrivacyPolicy">《隐私政策》</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 密码登录按钮(密码模式显示) -->
|
|
|
+ <button v-if="loginMode === 'password'" class="btn login-btn" @click="handlePhoneLogin">登录</button>
|
|
|
+
|
|
|
+ <!-- 微信快捷登录按钮(快捷模式显示) -->
|
|
|
+ <button v-if="loginMode === 'quick'" class="btn wechat-btn" open-type="getPhoneNumber"
|
|
|
+ @getphonenumber="handleWechatLogin" :loading="wechatLoading" :disabled="wechatLoading">快捷登录</button>
|
|
|
+
|
|
|
+ <!-- 登录方式切换链接 - 放在按钮正下方 -->
|
|
|
+ <view class="toggle-mode" @click="toggleMode">
|
|
|
+ {{ loginMode === 'quick' ? '账号密码登录' : '快捷登录' }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref } from 'vue'
|
|
|
+import { quickLogin, telEncrypt } from '@/utils/util.js'
|
|
|
+import { getLoginByPwdApi } from '@/api/user.js'
|
|
|
+import { useAppStore } from '@/stores/app'
|
|
|
+
|
|
|
+const appStore = useAppStore()
|
|
|
+const phone = ref('') // 手机号
|
|
|
+const password = ref('') // 密码
|
|
|
+const agree = ref(false) // 协议勾选状态
|
|
|
+const wechatLoading = ref(false) // 微信登录loading
|
|
|
+const loginMode = ref('quick') // 登录模式:quick-快捷登录,password-密码登录
|
|
|
+
|
|
|
+// 复选框组变化处理
|
|
|
+const onAgreeChange = (e) => {
|
|
|
+ agree.value = e.detail.value.includes('agree')
|
|
|
+}
|
|
|
+
|
|
|
+// 切换登录模式
|
|
|
+const toggleMode = () => {
|
|
|
+ loginMode.value = loginMode.value === 'quick' ? 'password' : 'quick'
|
|
|
+}
|
|
|
+
|
|
|
+// 手机号密码登录
|
|
|
+const handlePhoneLogin = async () => {
|
|
|
+ if (!phone.value) {
|
|
|
+ uni.showToast({ title: '请输入帐号', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (!password.value) {
|
|
|
+ uni.showToast({ title: '请输入密码', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (!agree.value) {
|
|
|
+ uni.showToast({ title: '请先同意用户协议和隐私政策', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const params = {
|
|
|
+ username: phone.value,
|
|
|
+ password: password.value
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ const res = await getLoginByPwdApi(params)
|
|
|
+ if (res.code == 200) {
|
|
|
+ uni.showToast({ title: '登录成功~', icon: 'none' })
|
|
|
+ appStore.UPDATE_TOKEN(res.data.access_token || res.data);
|
|
|
+ setTimeout(() => {
|
|
|
+ uni.navigateBack()
|
|
|
+ }, 200)
|
|
|
+ } else {
|
|
|
+ uni.showToast({ title: res.msg, icon: 'none' })
|
|
|
+ }
|
|
|
+ } catch (err) {
|
|
|
+ console.error('登录接口异常', err)
|
|
|
+ uni.showToast({ title: err, icon: 'none' })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 微信快捷登录
|
|
|
+const handleWechatLogin = async (e) => {
|
|
|
+ // 检查协议同意
|
|
|
+ if (!agree.value) {
|
|
|
+ uni.showToast({ title: '请先同意用户协议和隐私政策', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (wechatLoading.value) return
|
|
|
+ wechatLoading.value = true
|
|
|
+ uni.showLoading({ title: '登录中...', mask: true })
|
|
|
+
|
|
|
+ try {
|
|
|
+ await quickLogin(e, {
|
|
|
+ onSuccess: (result) => {
|
|
|
+ console.log('登录成功', result)
|
|
|
+ if (result.data) {
|
|
|
+ appStore.UPDATE_USERINFO(result.data)
|
|
|
+ }
|
|
|
+ uni.hideLoading()
|
|
|
+ uni.showToast({ title: '登录成功', icon: 'success' })
|
|
|
+ setTimeout(() => {
|
|
|
+ uni.navigateBack()
|
|
|
+ }, 1500)
|
|
|
+ },
|
|
|
+ onFail: (error) => {
|
|
|
+ console.error('登录失败', error)
|
|
|
+ uni.hideLoading()
|
|
|
+ let msg = error.message || '登录失败'
|
|
|
+ if (error.type === 'auth_denied') {
|
|
|
+ msg = '您拒绝了授权,无法登录'
|
|
|
+ uni.showModal({
|
|
|
+ title: '提示',
|
|
|
+ content: '需要手机号授权才能正常使用,请点击右上角菜单,选择「重新进入小程序」后重新授权',
|
|
|
+ showCancel: false
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ uni.showToast({ title: msg, icon: 'none' })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } catch (err) {
|
|
|
+ console.error('quickLogin 异常', err)
|
|
|
+ uni.hideLoading()
|
|
|
+ uni.showToast({ title: '登录异常', icon: 'none' })
|
|
|
+ } finally {
|
|
|
+ wechatLoading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 跳转用户协议
|
|
|
+const toUserAgreement = () => {
|
|
|
+ uni.navigateTo({
|
|
|
+ url: '/pages/webView/webView?title=用户协议&url=' + encodeURIComponent('https://rjsd.mychery.com/user_agreement.html')
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+// 跳转隐私政策
|
|
|
+const toPrivacyPolicy = () => {
|
|
|
+ uni.navigateTo({
|
|
|
+ url: '/pages/webView/webView?title=隐私政策&url=' + encodeURIComponent('https://rjsd.mychery.com/privacy_policy.html')
|
|
|
+ });
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="less">
|
|
|
+/* 页面容器 */
|
|
|
+.login-page {
|
|
|
+ width: 100%;
|
|
|
+ min-height: 100vh;
|
|
|
+ background: linear-gradient(135deg, #CFE9FF 0%, #F5F7FA 50.86%);
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ padding: 40rpx 80rpx;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+.logo-placeholder {
|
|
|
+ width: 100%;
|
|
|
+ margin: 120rpx 0rpx 90rpx 0rpx;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+
|
|
|
+ image {
|
|
|
+ width: 425rpx;
|
|
|
+ height: 100rpx;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 通用输入框包装 */
|
|
|
+.input-wrapper {
|
|
|
+ width: 100%;
|
|
|
+ padding: 24rpx 32rpx;
|
|
|
+ height: 88rpx;
|
|
|
+ background: #FFFFFF;
|
|
|
+ border-radius: 44rpx;
|
|
|
+ box-sizing: border-box;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ transition: border-color 0.2s;
|
|
|
+ margin-bottom: 32rpx;
|
|
|
+
|
|
|
+ &:focus-within {
|
|
|
+ border-color: #007AFF;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.input-field {
|
|
|
+ flex: 1;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #333;
|
|
|
+ background-color: transparent;
|
|
|
+ height: 88rpx;
|
|
|
+ line-height: 88rpx;
|
|
|
+ padding: 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* 协议行 */
|
|
|
+.agreement-row {
|
|
|
+ width: 100%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #4a5568;
|
|
|
+
|
|
|
+ checkbox-group {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.agree-checkbox {
|
|
|
+ transform: scale(0.9);
|
|
|
+ margin-right: 8rpx;
|
|
|
+}
|
|
|
+
|
|
|
+/* 覆盖 checkbox 样式 */
|
|
|
+::v-deep .agree-checkbox .wx-checkbox-input,
|
|
|
+::v-deep .agree-checkbox .uni-checkbox-input {
|
|
|
+ border-radius: 50%;
|
|
|
+ width: 36rpx;
|
|
|
+ height: 36rpx;
|
|
|
+ background-color: #ffffff;
|
|
|
+ border: 2rpx solid #ccc;
|
|
|
+}
|
|
|
+
|
|
|
+::v-deep .agree-checkbox .wx-checkbox-input.wx-checkbox-input-checked,
|
|
|
+::v-deep .agree-checkbox .uni-checkbox-input.uni-checkbox-input-checked {
|
|
|
+ background-color: #007AFF !important;
|
|
|
+ border-color: #007AFF !important;
|
|
|
+}
|
|
|
+
|
|
|
+::v-deep .agree-checkbox .wx-checkbox-input.wx-checkbox-input-checked::before,
|
|
|
+::v-deep .agree-checkbox .uni-checkbox-input.uni-checkbox-input-checked::before {
|
|
|
+ color: #ffffff !important;
|
|
|
+}
|
|
|
+
|
|
|
+.link-text {
|
|
|
+ color: #007AFF;
|
|
|
+ display: inline-block;
|
|
|
+}
|
|
|
+
|
|
|
+/* 登录方式切换链接 - 按钮正下方 */
|
|
|
+.toggle-mode {
|
|
|
+ width: 100%;
|
|
|
+ text-align: right;
|
|
|
+ color: #007AFF;
|
|
|
+ font-size: 28rpx;
|
|
|
+ margin-top: 30rpx; /* 与按钮保持适当间距 */
|
|
|
+ margin-bottom: 0;
|
|
|
+ padding: 10rpx 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* 按钮基础样式 */
|
|
|
+.btn {
|
|
|
+ width: 100%;
|
|
|
+ height: 88rpx;
|
|
|
+ border-radius: 44rpx;
|
|
|
+ font-size: 32rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ border: none;
|
|
|
+ color: #ffffff;
|
|
|
+ margin-bottom: 32rpx;
|
|
|
+ box-shadow: 0 8rpx 20rpx rgba(0, 122, 255, 0.25);
|
|
|
+ transition: opacity 0.2s;
|
|
|
+
|
|
|
+ &.login-btn {
|
|
|
+ background-color: #007AFF;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.wechat-btn {
|
|
|
+ background-color: #2DAB6C;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 重置按钮默认样式 */
|
|
|
+button {
|
|
|
+ padding: 0;
|
|
|
+ margin: 0;
|
|
|
+ line-height: 1.5;
|
|
|
+ background: none;
|
|
|
+ box-shadow: none;
|
|
|
+}
|
|
|
+button::after {
|
|
|
+ border: none;
|
|
|
+}
|
|
|
+</style>
|