初始化移动端提交
This commit is contained in:
145
sheep/components/s-auth-modal/components/change-mobile.vue
Normal file
145
sheep/components/s-auth-modal/components/change-mobile.vue
Normal file
@@ -0,0 +1,145 @@
|
||||
<!-- 绑定/更换手机号 changeMobile -->
|
||||
<template>
|
||||
<view>
|
||||
<!-- 标题栏 -->
|
||||
<view class="head-box ss-m-b-60">
|
||||
<view class="head-title ss-m-b-20">
|
||||
{{ userInfo.mobile ? '更换手机号' : '绑定手机号' }}
|
||||
</view>
|
||||
<view class="head-subtitle">为了您的账号安全,请使用本人手机号码</view>
|
||||
</view>
|
||||
|
||||
<!-- 表单项 -->
|
||||
<uni-forms
|
||||
ref="changeMobileRef"
|
||||
v-model="state.model"c
|
||||
:rules="state.rules"
|
||||
validateTrigger="bind"
|
||||
labelWidth="140"
|
||||
labelAlign="center"
|
||||
>
|
||||
<uni-forms-item name="mobile" label="手机号">
|
||||
<uni-easyinput
|
||||
placeholder="请输入手机号"
|
||||
v-model="state.model.mobile"
|
||||
:inputBorder="false"
|
||||
type="number"
|
||||
>
|
||||
<template v-slot:right>
|
||||
<button
|
||||
class="ss-reset-button code-btn-start"
|
||||
:disabled="state.isMobileEnd"
|
||||
:class="{ 'code-btn-end': state.isMobileEnd }"
|
||||
@tap="getSmsCode('changeMobile', state.model.mobile)"
|
||||
>
|
||||
{{ getSmsTimer('changeMobile') }}
|
||||
</button>
|
||||
</template>
|
||||
</uni-easyinput>
|
||||
</uni-forms-item>
|
||||
|
||||
<uni-forms-item name="code" label="验证码">
|
||||
<uni-easyinput
|
||||
placeholder="请输入验证码"
|
||||
v-model="state.model.code"
|
||||
:inputBorder="false"
|
||||
type="number"
|
||||
maxlength="4"
|
||||
>
|
||||
<template v-slot:right>
|
||||
<button class="ss-reset-button login-btn-start" @tap="changeMobileSubmit">
|
||||
确认
|
||||
</button>
|
||||
</template>
|
||||
</uni-easyinput>
|
||||
</uni-forms-item>
|
||||
</uni-forms>
|
||||
|
||||
<!-- 微信独有:读取手机号 -->
|
||||
<button
|
||||
v-if="'WechatMiniProgram' === sheep.$platform.name"
|
||||
class="ss-reset-button type-btn"
|
||||
open-type="getPhoneNumber"
|
||||
@getphonenumber="getPhoneNumber"
|
||||
>
|
||||
使用微信手机号
|
||||
</button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref, reactive, unref } from 'vue';
|
||||
import sheep from '@/sheep';
|
||||
import { code, mobile } from '@/sheep/validate/form';
|
||||
import { getSmsCode, getSmsTimer } from '@/sheep/hooks/useModal';
|
||||
import UserApi from '@/sheep/api/system/user';
|
||||
|
||||
const changeMobileRef = ref(null);
|
||||
const userInfo = computed(() => sheep.$store('user').userInfo);
|
||||
|
||||
// 数据
|
||||
const state = reactive({
|
||||
isMobileEnd: false, // 手机号输入完毕
|
||||
model: {
|
||||
mobile: '', // 手机号
|
||||
code: '', // 验证码
|
||||
},
|
||||
rules: {
|
||||
code,
|
||||
mobile,
|
||||
},
|
||||
});
|
||||
|
||||
// 绑定手机号
|
||||
async function changeMobileSubmit() {
|
||||
const validate = await unref(changeMobileRef)
|
||||
.validate()
|
||||
.catch((error) => {
|
||||
console.log('error: ', error);
|
||||
});
|
||||
if (!validate) {
|
||||
return;
|
||||
}
|
||||
// 提交更新请求
|
||||
const { code } = await UserApi.updateUserMobile(state.model);
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
sheep.$store('user').getInfo();
|
||||
// 绑定成功后返回上一页或首页
|
||||
setTimeout(() => {
|
||||
if (getCurrentPages().length > 1) {
|
||||
uni.navigateBack();
|
||||
} else {
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/menu'
|
||||
});
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
// 使用微信手机号
|
||||
async function getPhoneNumber(e) {
|
||||
if (e.detail.errMsg !== 'getPhoneNumber:ok') {
|
||||
return;
|
||||
}
|
||||
const result = await sheep.$platform.useProvider().bindUserPhoneNumber(e.detail);
|
||||
if (result) {
|
||||
sheep.$store('user').getInfo();
|
||||
// 绑定成功后返回上一页或首页
|
||||
setTimeout(() => {
|
||||
if (getCurrentPages().length > 1) {
|
||||
uni.navigateBack();
|
||||
} else {
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/menu'
|
||||
});
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../index.scss';
|
||||
</style>
|
||||
125
sheep/components/s-auth-modal/components/change-password.vue
Normal file
125
sheep/components/s-auth-modal/components/change-password.vue
Normal file
@@ -0,0 +1,125 @@
|
||||
<!-- 修改密码(登录时) -->
|
||||
<template>
|
||||
<view>
|
||||
<!-- 标题栏 -->
|
||||
<view class="head-box ss-m-b-60">
|
||||
<view class="head-title ss-m-b-20">修改密码</view>
|
||||
<view class="head-subtitle">如密码丢失或未设置,请点击忘记密码重新设置</view>
|
||||
</view>
|
||||
|
||||
<!-- 表单项 -->
|
||||
<uni-forms
|
||||
ref="changePasswordRef"
|
||||
v-model="state.model"
|
||||
:rules="state.rules"
|
||||
validateTrigger="bind"
|
||||
labelWidth="140"
|
||||
labelAlign="center"
|
||||
>
|
||||
<uni-forms-item name="code" label="验证码">
|
||||
<uni-easyinput
|
||||
placeholder="请输入验证码"
|
||||
v-model="state.model.code"
|
||||
type="number"
|
||||
maxlength="4"
|
||||
:inputBorder="false"
|
||||
>
|
||||
<template v-slot:right>
|
||||
<button
|
||||
class="ss-reset-button code-btn code-btn-start"
|
||||
:disabled="state.isMobileEnd"
|
||||
:class="{ 'code-btn-end': state.isMobileEnd }"
|
||||
@tap="getSmsCode('changePassword')"
|
||||
>
|
||||
{{ getSmsTimer('resetPassword') }}
|
||||
</button>
|
||||
</template>
|
||||
</uni-easyinput>
|
||||
</uni-forms-item>
|
||||
|
||||
<uni-forms-item name="reNewPassword" label="密码">
|
||||
<uni-easyinput
|
||||
type="password"
|
||||
placeholder="请输入密码"
|
||||
v-model="state.model.password"
|
||||
:inputBorder="false"
|
||||
>
|
||||
<template v-slot:right>
|
||||
<button class="ss-reset-button login-btn-start" @tap="changePasswordSubmit">
|
||||
确认
|
||||
</button>
|
||||
</template>
|
||||
</uni-easyinput>
|
||||
</uni-forms-item>
|
||||
</uni-forms>
|
||||
|
||||
<button class="ss-reset-button type-btn" @tap="goBack">
|
||||
取消修改
|
||||
</button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, unref } from 'vue';
|
||||
import { code, password } from '@/sheep/validate/form';
|
||||
import { getSmsCode, getSmsTimer } from '@/sheep/hooks/useModal';
|
||||
import UserApi from '@/sheep/api/system/user';
|
||||
|
||||
const changePasswordRef = ref(null);
|
||||
|
||||
// 数据
|
||||
const state = reactive({
|
||||
model: {
|
||||
mobile: '', // 手机号
|
||||
code: '', // 验证码
|
||||
password: '', // 密码
|
||||
},
|
||||
rules: {
|
||||
code,
|
||||
password,
|
||||
},
|
||||
});
|
||||
|
||||
// 返回上一页
|
||||
function goBack() {
|
||||
if (getCurrentPages().length > 1) {
|
||||
uni.navigateBack();
|
||||
} else {
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/menu'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 更改密码
|
||||
async function changePasswordSubmit() {
|
||||
// 参数校验
|
||||
const validate = await unref(changePasswordRef)
|
||||
.validate()
|
||||
.catch((error) => {
|
||||
console.log('error: ', error);
|
||||
});
|
||||
if (!validate) {
|
||||
return;
|
||||
}
|
||||
// 发起请求
|
||||
const { code } = await UserApi.updateUserPassword(state.model);
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
// 成功后返回上一页或首页
|
||||
setTimeout(() => {
|
||||
if (getCurrentPages().length > 1) {
|
||||
uni.navigateBack();
|
||||
} else {
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/menu'
|
||||
});
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../index.scss';
|
||||
</style>
|
||||
160
sheep/components/s-auth-modal/components/mp-authorization.vue
Normal file
160
sheep/components/s-auth-modal/components/mp-authorization.vue
Normal file
@@ -0,0 +1,160 @@
|
||||
<!-- 微信授权信息 mpAuthorization -->
|
||||
<template>
|
||||
<view>
|
||||
<!-- 标题栏 -->
|
||||
<view class="head-box ss-m-b-60 ss-flex-col">
|
||||
<view class="ss-flex ss-m-b-20">
|
||||
<view class="head-title ss-m-r-40 head-title-animation">授权信息</view>
|
||||
</view>
|
||||
<view class="head-subtitle">完善您的头像、昵称、手机号</view>
|
||||
</view>
|
||||
|
||||
<!-- 表单项 -->
|
||||
<uni-forms
|
||||
ref="accountLoginRef"
|
||||
v-model="state.model"
|
||||
:rules="state.rules"
|
||||
validateTrigger="bind"
|
||||
labelWidth="140"
|
||||
labelAlign="center"
|
||||
>
|
||||
<!-- 获取头像昵称:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/userProfile.html -->
|
||||
<uni-forms-item name="avatar" label="头像">
|
||||
<button
|
||||
class="ss-reset-button avatar-btn"
|
||||
open-type="chooseAvatar"
|
||||
@chooseavatar="onChooseAvatar"
|
||||
>
|
||||
<image
|
||||
class="avatar-img"
|
||||
:src="sheep.$url.cdn(state.model.avatar)"
|
||||
mode="aspectFill"
|
||||
@tap="sheep.$router.go('/pages/user/info')"
|
||||
/>
|
||||
<text class="cicon-forward" />
|
||||
</button>
|
||||
</uni-forms-item>
|
||||
<uni-forms-item name="nickname" label="昵称">
|
||||
<uni-easyinput
|
||||
type="nickname"
|
||||
placeholder="请输入昵称"
|
||||
v-model="state.model.nickname"
|
||||
:inputBorder="false"
|
||||
/>
|
||||
</uni-forms-item>
|
||||
<view class="foot-box">
|
||||
<button class="ss-reset-button authorization-btn" @tap="onConfirm"> 确认授权 </button>
|
||||
</view>
|
||||
</uni-forms>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref, reactive } from 'vue';
|
||||
import sheep from '@/sheep';
|
||||
import FileApi from '@/sheep/api/infra/file';
|
||||
import UserApi from '@/sheep/api/system/user';
|
||||
|
||||
const props = defineProps({
|
||||
agreeStatus: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const userInfo = computed(() => sheep.$store('user').userInfo);
|
||||
|
||||
const accountLoginRef = ref(null);
|
||||
|
||||
// 数据
|
||||
const state = reactive({
|
||||
model: {
|
||||
nickname: userInfo.value.nickname,
|
||||
avatar: userInfo.value.avatar,
|
||||
},
|
||||
rules: {},
|
||||
disabledStyle: {
|
||||
color: '#999',
|
||||
disableColor: '#fff',
|
||||
},
|
||||
});
|
||||
|
||||
// 选择头像(来自微信)
|
||||
function onChooseAvatar(e) {
|
||||
const tempUrl = e.detail.avatarUrl || '';
|
||||
uploadAvatar(tempUrl);
|
||||
}
|
||||
|
||||
// 选择头像(来自文件系统)
|
||||
async function uploadAvatar(tempUrl) {
|
||||
if (!tempUrl) {
|
||||
return;
|
||||
}
|
||||
let { data } = await FileApi.uploadFile(tempUrl);
|
||||
state.model.avatar = data;
|
||||
}
|
||||
|
||||
// 确认授权
|
||||
async function onConfirm() {
|
||||
const { model } = state;
|
||||
const { nickname, avatar } = model;
|
||||
if (!nickname) {
|
||||
sheep.$helper.toast('请输入昵称');
|
||||
return;
|
||||
}
|
||||
if (!avatar) {
|
||||
sheep.$helper.toast('请选择头像');
|
||||
return;
|
||||
}
|
||||
// 发起更新
|
||||
const { code } = await UserApi.updateUser({
|
||||
avatar: state.model.avatar,
|
||||
nickname: state.model.nickname,
|
||||
});
|
||||
// 更新成功
|
||||
if (code === 0) {
|
||||
sheep.$helper.toast('授权成功');
|
||||
await sheep.$store('user').getInfo();
|
||||
// 授权成功后返回上一页或首页
|
||||
setTimeout(() => {
|
||||
if (getCurrentPages().length > 1) {
|
||||
uni.navigateBack();
|
||||
} else {
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/menu'
|
||||
});
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../index.scss';
|
||||
|
||||
.foot-box {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.authorization-btn {
|
||||
width: 686rpx;
|
||||
height: 80rpx;
|
||||
background-color: var(--ui-BG-Main);
|
||||
border-radius: 40rpx;
|
||||
color: #fff;
|
||||
}
|
||||
.avatar-img {
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 36rpx;
|
||||
}
|
||||
.cicon-forward {
|
||||
font-size: 30rpx;
|
||||
color: #595959;
|
||||
}
|
||||
.avatar-btn {
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
126
sheep/components/s-auth-modal/components/reset-password.vue
Normal file
126
sheep/components/s-auth-modal/components/reset-password.vue
Normal file
@@ -0,0 +1,126 @@
|
||||
<!-- 重置密码(未登录时) -->
|
||||
<template>
|
||||
<view>
|
||||
<!-- 标题栏 -->
|
||||
<view class="head-box ss-m-b-60">
|
||||
<view class="head-title ss-m-b-20">重置密码</view>
|
||||
<view class="head-subtitle">为了您的账号安全,设置密码前请先进行安全验证</view>
|
||||
</view>
|
||||
|
||||
<!-- 表单项 -->
|
||||
<uni-forms
|
||||
ref="resetPasswordRef"
|
||||
v-model="state.model"
|
||||
:rules="state.rules"
|
||||
validateTrigger="bind"
|
||||
labelWidth="140"
|
||||
labelAlign="center"
|
||||
>
|
||||
<uni-forms-item name="mobile" label="手机号">
|
||||
<uni-easyinput
|
||||
placeholder="请输入手机号"
|
||||
v-model="state.model.mobile"
|
||||
type="number"
|
||||
:inputBorder="false"
|
||||
>
|
||||
<template v-slot:right>
|
||||
<button
|
||||
class="ss-reset-button code-btn code-btn-start"
|
||||
:disabled="state.isMobileEnd"
|
||||
:class="{ 'code-btn-end': state.isMobileEnd }"
|
||||
@tap="getSmsCode('resetPassword', state.model.mobile)"
|
||||
>
|
||||
{{ getSmsTimer('resetPassword') }}
|
||||
</button>
|
||||
</template>
|
||||
</uni-easyinput>
|
||||
</uni-forms-item>
|
||||
|
||||
<uni-forms-item name="code" label="验证码">
|
||||
<uni-easyinput
|
||||
placeholder="请输入验证码"
|
||||
v-model="state.model.code"
|
||||
type="number"
|
||||
maxlength="4"
|
||||
:inputBorder="false"
|
||||
/>
|
||||
</uni-forms-item>
|
||||
|
||||
<uni-forms-item name="password" label="密码">
|
||||
<uni-easyinput
|
||||
type="password"
|
||||
placeholder="请输入密码"
|
||||
v-model="state.model.password"
|
||||
:inputBorder="false"
|
||||
>
|
||||
<template v-slot:right>
|
||||
<button class="ss-reset-button login-btn-start" @tap="resetPasswordSubmit">
|
||||
确认
|
||||
</button>
|
||||
</template>
|
||||
</uni-easyinput>
|
||||
</uni-forms-item>
|
||||
</uni-forms>
|
||||
|
||||
<button v-if="!isLogin" class="ss-reset-button type-btn" @tap="goToLogin">
|
||||
返回登录
|
||||
</button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref, reactive, unref } from 'vue';
|
||||
import sheep from '@/sheep';
|
||||
import { code, mobile, password } from '@/sheep/validate/form';
|
||||
import { getSmsCode, getSmsTimer } from '@/sheep/hooks/useModal';
|
||||
import UserApi from '@/sheep/api/system/user';
|
||||
|
||||
// 跳转到登录页
|
||||
function goToLogin() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/login/index'
|
||||
});
|
||||
}
|
||||
|
||||
const resetPasswordRef = ref(null);
|
||||
const isLogin = computed(() => sheep.$store('user').isLogin);
|
||||
|
||||
// 数据
|
||||
const state = reactive({
|
||||
isMobileEnd: false, // 手机号输入完毕
|
||||
model: {
|
||||
mobile: '', // 手机号
|
||||
code: '', // 验证码
|
||||
password: '', // 密码
|
||||
},
|
||||
rules: {
|
||||
code,
|
||||
mobile,
|
||||
password,
|
||||
},
|
||||
});
|
||||
|
||||
// 重置密码
|
||||
const resetPasswordSubmit = async () => {
|
||||
// 参数校验
|
||||
const validate = await unref(resetPasswordRef)
|
||||
.validate()
|
||||
.catch((error) => {
|
||||
console.log('error: ', error);
|
||||
});
|
||||
if (!validate) {
|
||||
return;
|
||||
}
|
||||
// 发起请求
|
||||
const { code } = await UserApi.resetUserPassword(state.model);
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
// 成功后,用户重新登录
|
||||
goToLogin();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../index.scss';
|
||||
</style>
|
||||
430
sheep/components/s-auth-modal/components/unified-login.vue
Normal file
430
sheep/components/s-auth-modal/components/unified-login.vue
Normal file
@@ -0,0 +1,430 @@
|
||||
<!-- 统一登录组件 - 整合账号密码登录和短信登录 -->
|
||||
<template>
|
||||
<view>
|
||||
<!-- 标题栏 -->
|
||||
<view class="head-box ss-m-b-60 ss-flex-col">
|
||||
<!-- 登录方式切换标签 -->
|
||||
<view class="ss-flex ss-m-b-20">
|
||||
<view
|
||||
class="head-title ss-m-r-40"
|
||||
:class="{ 'head-title-active': loginType === 'account', 'head-title-animation': loginType === 'account' }"
|
||||
@tap="switchLoginType('account')"
|
||||
>
|
||||
账号登录
|
||||
</view>
|
||||
<!-- <view
|
||||
class="head-title"
|
||||
:class="{ 'head-title-active': loginType === 'sms', 'head-title-animation': loginType === 'sms' }"
|
||||
@tap="switchLoginType('sms')"
|
||||
>
|
||||
短信登录
|
||||
</view> -->
|
||||
</view>
|
||||
<!-- 副标题 -->
|
||||
<view class="head-subtitle">
|
||||
{{ loginType === 'account' ? '如果未设置过密码,请点击忘记密码' : '未注册的手机号,验证后自动注册账号' }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 账号密码登录表单 -->
|
||||
<uni-forms
|
||||
v-if="loginType === 'account'"
|
||||
ref="accountLoginRef"
|
||||
v-model="accountState.model"
|
||||
:rules="accountState.rules"
|
||||
validateTrigger="bind"
|
||||
labelWidth="140"
|
||||
labelAlign="center"
|
||||
>
|
||||
<uni-forms-item name="username" label="账号">
|
||||
<uni-easyinput placeholder="请输入账号" v-model="accountState.model.username" :inputBorder="false">
|
||||
<template v-slot:right>
|
||||
<!-- <button class="ss-reset-button forgot-btn" @tap="showAuthModal('resetPassword')">
|
||||
忘记密码
|
||||
</button> -->
|
||||
</template>
|
||||
</uni-easyinput>
|
||||
</uni-forms-item>
|
||||
|
||||
<uni-forms-item name="password" label="密码">
|
||||
<uni-easyinput
|
||||
type="password"
|
||||
placeholder="请输入密码"
|
||||
v-model="accountState.model.password"
|
||||
:inputBorder="false"
|
||||
>
|
||||
<template v-slot:right>
|
||||
<button class="ss-reset-button login-btn-start" @tap="handleAccountLogin">登录</button>
|
||||
</template>
|
||||
</uni-easyinput>
|
||||
</uni-forms-item>
|
||||
</uni-forms>
|
||||
|
||||
<!-- 短信登录表单 -->
|
||||
<uni-forms
|
||||
v-if="loginType === 'sms'"
|
||||
ref="smsLoginRef"
|
||||
v-model="smsState.model"
|
||||
:rules="smsState.rules"
|
||||
validateTrigger="bind"
|
||||
labelWidth="140"
|
||||
labelAlign="center"
|
||||
>
|
||||
<uni-forms-item name="mobile" label="手机号">
|
||||
<uni-easyinput
|
||||
placeholder="请输入手机号"
|
||||
v-model="smsState.model.mobile"
|
||||
:inputBorder="false"
|
||||
type="number"
|
||||
>
|
||||
<template v-slot:right>
|
||||
<button
|
||||
class="ss-reset-button code-btn code-btn-start"
|
||||
:disabled="!canSendSms"
|
||||
:class="{ 'code-btn-end': !canSendSms }"
|
||||
@tap="checkAgreementAndGetSmsCode"
|
||||
>
|
||||
{{ smsTimer }}
|
||||
</button>
|
||||
</template>
|
||||
</uni-easyinput>
|
||||
</uni-forms-item>
|
||||
|
||||
<uni-forms-item name="code" label="验证码">
|
||||
<uni-easyinput
|
||||
placeholder="请输入验证码"
|
||||
v-model="smsState.model.code"
|
||||
:inputBorder="false"
|
||||
type="number"
|
||||
maxlength="4"
|
||||
>
|
||||
<template v-slot:right>
|
||||
<button class="ss-reset-button login-btn-start" @tap="handleSmsLogin">登录</button>
|
||||
</template>
|
||||
</uni-easyinput>
|
||||
</uni-forms-item>
|
||||
</uni-forms>
|
||||
|
||||
<!-- 验证码弹窗 -->
|
||||
<s-verify
|
||||
ref="verifyRef"
|
||||
:captcha-type="captchaType"
|
||||
mode="pop"
|
||||
@success="onCaptchaSuccess"
|
||||
@error="onCaptchaError"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, unref, computed, onUnmounted } from 'vue';
|
||||
import sheep from '@/sheep';
|
||||
import { username, password, mobile, code } from '@/sheep/validate/form';
|
||||
import { showAuthModal, getSmsCode, useSmsTimer } from '@/sheep/hooks/useModal';
|
||||
import AuthUtil from '@/sheep/api/system/auth';
|
||||
import SVerify from '@/sheep/components/s-verify/s-verify.vue';
|
||||
import { navigateAfterLogin } from '@/sheep/helper/login-redirect';
|
||||
|
||||
const accountLoginRef = ref(null);
|
||||
const smsLoginRef = ref(null);
|
||||
const verifyRef = ref(null);
|
||||
|
||||
const emits = defineEmits(['onConfirm']);
|
||||
|
||||
const props = defineProps({
|
||||
agreeStatus: {
|
||||
type: [Boolean, null],
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
// 登录方式:account(账号) 或 sms(短信)
|
||||
const loginType = ref('account');
|
||||
|
||||
// 验证码相关
|
||||
const appStore = sheep.$store('app');
|
||||
const captchaType = ref('blockPuzzle');
|
||||
const captchaEnable = computed(() => appStore.captchaEnable !== false);
|
||||
const pendingLoginData = ref(null);
|
||||
|
||||
// 短信验证码计时器
|
||||
const { timer: smsTimer, cleanup } = useSmsTimer('smsLogin');
|
||||
|
||||
// 组件卸载时清理定时器
|
||||
onUnmounted(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
// 账号登录数据
|
||||
const accountState = reactive({
|
||||
model: {
|
||||
username: '', // 账号
|
||||
password: '', // 密码
|
||||
captchaCode: '', // 图形验证码
|
||||
captchaVerification: '', // 验证码验证结果
|
||||
},
|
||||
rules: {
|
||||
username,
|
||||
password,
|
||||
},
|
||||
});
|
||||
|
||||
// 短信登录数据
|
||||
const smsState = reactive({
|
||||
model: {
|
||||
mobile: '', // 手机号
|
||||
code: '', // 验证码
|
||||
captchaVerification: '', // 验证码验证结果
|
||||
},
|
||||
rules: {
|
||||
mobile,
|
||||
code,
|
||||
},
|
||||
});
|
||||
|
||||
// 是否可以发送短信验证码
|
||||
const canSendSms = computed(() => {
|
||||
return smsTimer.value === '获取验证码' && props.agreeStatus === true;
|
||||
});
|
||||
|
||||
// 切换登录方式
|
||||
function switchLoginType(type) {
|
||||
loginType.value = type;
|
||||
}
|
||||
|
||||
// 显示验证码弹窗
|
||||
function showCaptcha() {
|
||||
if (verifyRef.value) {
|
||||
verifyRef.value.show();
|
||||
}
|
||||
}
|
||||
|
||||
// 验证码验证成功回调
|
||||
function onCaptchaSuccess(data) {
|
||||
if (pendingLoginData.value) {
|
||||
pendingLoginData.value.captchaVerification = data.captchaVerification;
|
||||
if (loginType.value === 'account') {
|
||||
accountState.model.captchaVerification = data.captchaVerification;
|
||||
} else {
|
||||
smsState.model.captchaVerification = data.captchaVerification;
|
||||
}
|
||||
|
||||
// 执行待定的登录请求
|
||||
if (loginType.value === 'account') {
|
||||
performAccountLogin(pendingLoginData.value);
|
||||
} else {
|
||||
performSmsLogin(pendingLoginData.value);
|
||||
}
|
||||
|
||||
pendingLoginData.value = null;
|
||||
}
|
||||
}
|
||||
|
||||
// 验证码验证失败回调
|
||||
function onCaptchaError(error) {
|
||||
sheep.$helper.toast(error?.message || '验证码验证失败');
|
||||
pendingLoginData.value = null;
|
||||
}
|
||||
|
||||
// 处理账号登录点击
|
||||
async function handleAccountLogin() {
|
||||
// 表单验证
|
||||
const validate = await unref(accountLoginRef)
|
||||
.validate()
|
||||
.catch((error) => {
|
||||
console.log('表单验证失败: ', error);
|
||||
});
|
||||
if (!validate) return;
|
||||
|
||||
accountState.model.captchaVerification = '';
|
||||
|
||||
// 检查协议状态
|
||||
if (props.agreeStatus !== true) {
|
||||
emits('onConfirm', true);
|
||||
sheep.$helper.toast('请先勾选协议');
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果启用验证码,先显示验证码
|
||||
if (captchaEnable.value) {
|
||||
pendingLoginData.value = { ...accountState.model };
|
||||
showCaptcha();
|
||||
} else {
|
||||
// 直接登录
|
||||
performAccountLogin(accountState.model);
|
||||
}
|
||||
}
|
||||
|
||||
// 执行账号登录
|
||||
async function performAccountLogin(loginData) {
|
||||
try {
|
||||
const { code } = await AuthUtil.login(loginData);
|
||||
if (code === 0) {
|
||||
sheep.$helper.toast('登录成功');
|
||||
navigateAfterLogin();
|
||||
}
|
||||
} catch (error) {
|
||||
sheep.$helper.toast(error.message || '登录失败');
|
||||
} finally {
|
||||
accountState.model.captchaVerification = '';
|
||||
}
|
||||
}
|
||||
|
||||
// 处理短信登录点击
|
||||
async function handleSmsLogin() {
|
||||
// 表单验证
|
||||
const validate = await unref(smsLoginRef)
|
||||
.validate()
|
||||
.catch((error) => {
|
||||
console.log('表单验证失败: ', error);
|
||||
});
|
||||
if (!validate) return;
|
||||
|
||||
smsState.model.captchaVerification = '';
|
||||
|
||||
// 检查协议状态
|
||||
if (props.agreeStatus !== true) {
|
||||
emits('onConfirm', true);
|
||||
sheep.$helper.toast('请先勾选协议');
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果启用验证码,先显示验证码
|
||||
if (captchaEnable.value) {
|
||||
pendingLoginData.value = { ...smsState.model };
|
||||
showCaptcha();
|
||||
} else {
|
||||
// 直接登录
|
||||
performSmsLogin(smsState.model);
|
||||
}
|
||||
}
|
||||
|
||||
// 执行短信登录
|
||||
async function performSmsLogin(loginData) {
|
||||
try {
|
||||
const { code } = await AuthUtil.smsLogin(loginData);
|
||||
if (code === 0) {
|
||||
sheep.$helper.toast('登录成功');
|
||||
navigateAfterLogin();
|
||||
}
|
||||
} catch (error) {
|
||||
sheep.$helper.toast(error.message || '登录失败');
|
||||
} finally {
|
||||
smsState.model.captchaVerification = '';
|
||||
}
|
||||
}
|
||||
|
||||
// 检查协议并获取短信验证码
|
||||
async function checkAgreementAndGetSmsCode() {
|
||||
// 检查协议状态
|
||||
if (props.agreeStatus !== true) {
|
||||
emits('onConfirm', true);
|
||||
sheep.$helper.toast('请先勾选协议');
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用现有的getSmsCode函数
|
||||
getSmsCode('smsLogin', smsState.model.mobile);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../index.scss';
|
||||
|
||||
// 标题样式增强
|
||||
.head-title {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
color: var(--ui-BG-Main);
|
||||
}
|
||||
}
|
||||
|
||||
.head-title-active {
|
||||
color: var(--ui-BG-Main);
|
||||
font-weight: 600;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -8px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 20px;
|
||||
height: 2px;
|
||||
background: var(--ui-BG-Main);
|
||||
border-radius: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.head-title-animation {
|
||||
animation: fadeIn 0.3s ease;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0.6;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 覆盖登录按钮样式,使用主题色
|
||||
.login-btn-start {
|
||||
background: var(--ui-BG-Main) !important;
|
||||
border: none !important;
|
||||
|
||||
&:hover {
|
||||
background: var(--ui-BG-Main-1) !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 覆盖验证码按钮样式,使用主题色
|
||||
.code-btn-start {
|
||||
border: 2rpx solid var(--ui-BG-Main) !important;
|
||||
color: var(--ui-BG-Main) !important;
|
||||
|
||||
&:hover {
|
||||
background: var(--ui-BG-Main-tag) !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 覆盖协议链接样式,使用主题色
|
||||
:deep(.tcp-text) {
|
||||
color: var(--ui-BG-Main) !important;
|
||||
}
|
||||
|
||||
// 确保表单输入框焦点状态也使用主题色
|
||||
:deep(.uni-easyinput__content-input) {
|
||||
&:focus {
|
||||
border-color: var(--ui-BG-Main) !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 确保uni-forms的错误提示等也使用合适的颜色
|
||||
:deep(.uni-forms-item__error) {
|
||||
color: #ff4d4f !important;
|
||||
}
|
||||
|
||||
// 按钮悬停状态优化
|
||||
.login-btn-start {
|
||||
transition: all 0.3s ease !important;
|
||||
|
||||
&:active {
|
||||
background: var(--ui-BG-Main-1) !important;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
}
|
||||
|
||||
.code-btn-start {
|
||||
transition: all 0.3s ease !important;
|
||||
|
||||
&:active {
|
||||
background: var(--ui-BG-Main-tag) !important;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
154
sheep/components/s-auth-modal/index.scss
Normal file
154
sheep/components/s-auth-modal/index.scss
Normal file
@@ -0,0 +1,154 @@
|
||||
@keyframes title-animation {
|
||||
0% {
|
||||
font-size: 32rpx;
|
||||
}
|
||||
100% {
|
||||
font-size: 36rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.login-wrap {
|
||||
padding: 50rpx 34rpx;
|
||||
min-height: 500rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 20rpx 20rpx 0 0;
|
||||
}
|
||||
|
||||
.head-box {
|
||||
.head-title {
|
||||
min-width: 160rpx;
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333333;
|
||||
line-height: 36rpx;
|
||||
}
|
||||
.head-title-active {
|
||||
width: 160rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #999;
|
||||
line-height: 36rpx;
|
||||
}
|
||||
.head-title-animation {
|
||||
animation-name: title-animation;
|
||||
animation-duration: 0.1s;
|
||||
animation-timing-function: ease-out;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
.head-title-line {
|
||||
position: relative;
|
||||
&::before {
|
||||
content: '';
|
||||
width: 1rpx;
|
||||
height: 34rpx;
|
||||
background-color: #e4e7ed;
|
||||
position: absolute;
|
||||
left: -30rpx;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
.head-subtitle {
|
||||
font-size: 26rpx;
|
||||
font-weight: 400;
|
||||
color: #afb6c0;
|
||||
text-align: left;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
// .code-btn[disabled] {
|
||||
// background-color: #fff;
|
||||
// }
|
||||
.code-btn-start {
|
||||
width: 160rpx;
|
||||
height: 56rpx;
|
||||
line-height: normal;
|
||||
border: 2rpx solid var(--ui-BG-Main, #0055A2) !important;
|
||||
border-radius: 28rpx;
|
||||
font-size: 26rpx;
|
||||
font-weight: 400;
|
||||
color: var(--ui-BG-Main, #0055A2) !important;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.forgot-btn {
|
||||
width: 160rpx;
|
||||
line-height: 56rpx;
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.login-btn-start {
|
||||
width: 158rpx;
|
||||
height: 56rpx;
|
||||
line-height: normal;
|
||||
background: var(--ui-BG-Main, #0055A2) !important;
|
||||
border-radius: 28rpx;
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
color: #fff !important;
|
||||
border: none;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.type-btn {
|
||||
padding: 20rpx;
|
||||
margin: 40rpx auto;
|
||||
width: 200rpx;
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.auto-login-box {
|
||||
width: 100%;
|
||||
.auto-login-btn {
|
||||
width: 68rpx;
|
||||
height: 68rpx;
|
||||
border-radius: 50%;
|
||||
margin: 0 30rpx;
|
||||
}
|
||||
.auto-login-img {
|
||||
width: 68rpx;
|
||||
height: 68rpx;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.agreement-box {
|
||||
margin: 80rpx auto 0;
|
||||
.protocol-check {
|
||||
transform: scale(0.7);
|
||||
}
|
||||
.agreement-text {
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
color: #999999;
|
||||
.tcp-text {
|
||||
color: var(--ui-BG-Main, #0055A2) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 修改密码
|
||||
.editPwd-btn-box {
|
||||
.save-btn {
|
||||
width: 690rpx;
|
||||
line-height: 70rpx;
|
||||
background: var(--ui-BG-Main, #0055A2) !important;
|
||||
border-radius: 35rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #ffffff !important;
|
||||
}
|
||||
.forgot-btn {
|
||||
width: 690rpx;
|
||||
line-height: 70rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user