| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- <!-- 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>
|