首次完整推送,
V:1.20240808.006
This commit is contained in:
@ -0,0 +1,73 @@
|
||||
<template>
|
||||
<view @click="onClick" :style="{width,height}" style="justify-content: center;">
|
||||
<image v-if="cSrc" :style="{width,height}" :src="cSrc" :mode="mode"></image>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* cloud-image
|
||||
* @description 兼容普通资源和unicloud图片资源渲染的组件
|
||||
* @property {String} mode 图片裁剪、缩放的模式。默认为widthFix,支持所有image组件的mode值
|
||||
* @property {String} src 资源完了链接或uniCloud云存储资源的fileid
|
||||
* @property {String} width 图片的宽,默认为:100rpx
|
||||
* @property {String} height 图片的高,默认为:100rpx
|
||||
* @event {Function} click 点击 cloud-image 触发事件
|
||||
*/
|
||||
export default {
|
||||
name: "cloud-image",
|
||||
emits:['click'],
|
||||
props: {
|
||||
mode: {
|
||||
type:String,
|
||||
default () {
|
||||
return 'widthFix'
|
||||
}
|
||||
},
|
||||
src: {
|
||||
// type:String,
|
||||
default () {
|
||||
return ""
|
||||
}
|
||||
},
|
||||
width: {
|
||||
type:String,
|
||||
default () {
|
||||
return '100rpx'
|
||||
}
|
||||
},
|
||||
height: {
|
||||
type:String,
|
||||
default () {
|
||||
return '100rpx'
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
src:{
|
||||
handler(src) {
|
||||
if (src&&src.substring(0, 8) == "cloud://") {
|
||||
uniCloud.getTempFileURL({
|
||||
fileList: [src]
|
||||
}).then(res=>{
|
||||
this.cSrc = res.fileList[0].tempFileURL
|
||||
})
|
||||
}else{
|
||||
this.cSrc = src
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
onClick(){
|
||||
this.$emit('click')
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
cSrc:false
|
||||
};
|
||||
}
|
||||
}
|
||||
</script>
|
@ -0,0 +1,167 @@
|
||||
<template>
|
||||
<view class="root" v-if="agreements.length">
|
||||
<template v-if="needAgreements">
|
||||
<checkbox-group @change="setAgree">
|
||||
<label class="checkbox-box">
|
||||
<checkbox :checked="isAgree" style="transform: scale(0.5);margin-right: -6px;" />
|
||||
<text class="text">同意</text>
|
||||
</label>
|
||||
</checkbox-group>
|
||||
<view class="content">
|
||||
<view class="item" v-for="(agreement,index) in agreements" :key="index">
|
||||
<text class="agreement text" @click="navigateTo(agreement)">{{agreement.title}}</text>
|
||||
<text class="text and" v-if="hasAnd(agreements,index)" space="nbsp"> 和 </text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 弹出式 -->
|
||||
<uni-popup v-if="needAgreements||needPopupAgreements" ref="popupAgreement" type="center">
|
||||
<uni-popup-dialog confirmText="同意" @confirm="popupConfirm">
|
||||
<view class="content">
|
||||
<text class="text">请先阅读并同意</text>
|
||||
<view class="item" v-for="(agreement,index) in agreements" :key="index">
|
||||
<text class="agreement text" @click="navigateTo(agreement)">{{agreement.title}}</text>
|
||||
<text class="text and" v-if="hasAnd(agreements,index)" space="nbsp"> 和 </text>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup-dialog>
|
||||
</uni-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import config from '@/uni_modules/uni-id-pages/config.js'
|
||||
let retryFun = ()=>console.log('为定义')
|
||||
/**
|
||||
* uni-id-pages-agreements
|
||||
* @description 用户服务协议和隐私政策条款组件
|
||||
* @property {String,Boolean} scope = [register|login] 作用于哪种场景如:register 注册(包括登录并注册,如:微信登录、苹果登录、短信验证码登录)、login 登录。默认值为:register
|
||||
*/
|
||||
export default {
|
||||
name: "uni-agreements",
|
||||
computed: {
|
||||
agreements() {
|
||||
if(!config.agreements){
|
||||
return []
|
||||
}
|
||||
let {serviceUrl,privacyUrl} = config.agreements
|
||||
return [
|
||||
{
|
||||
url:serviceUrl,
|
||||
title:"用户服务协议"
|
||||
},
|
||||
{
|
||||
url:privacyUrl,
|
||||
title:"隐私政策条款"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
props: {
|
||||
scope: {
|
||||
type: String,
|
||||
default(){
|
||||
return 'register'
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
popupConfirm(){
|
||||
this.isAgree = true
|
||||
retryFun()
|
||||
// this.$emit('popupConfirm')
|
||||
},
|
||||
popup(Fun){
|
||||
this.needPopupAgreements = true
|
||||
// this.needAgreements = true
|
||||
this.$nextTick(()=>{
|
||||
if(Fun){
|
||||
retryFun = Fun
|
||||
}
|
||||
this.$refs.popupAgreement.open()
|
||||
})
|
||||
},
|
||||
navigateTo({
|
||||
url,
|
||||
title
|
||||
}) {
|
||||
uni.navigateTo({
|
||||
url: '/uni_modules/uni-id-pages/pages/common/webview/webview?url=' + url + '&title=' + title,
|
||||
success: res => {},
|
||||
fail: () => {},
|
||||
complete: () => {}
|
||||
});
|
||||
},
|
||||
hasAnd(agreements, index) {
|
||||
return agreements.length - 1 > index
|
||||
},
|
||||
setAgree(e) {
|
||||
this.isAgree = !this.isAgree
|
||||
this.$emit('setAgree', this.isAgree)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.needAgreements = (config?.agreements?.scope || []).includes(this.scope)
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isAgree: false,
|
||||
needAgreements:true,
|
||||
needPopupAgreements:false
|
||||
};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* #ifndef APP-NVUE */
|
||||
view {
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
.root {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
color: #8a8f8b;
|
||||
}
|
||||
|
||||
.checkbox-box ,.uni-label-pointer{
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.item {
|
||||
flex-direction: row;
|
||||
}
|
||||
.text{
|
||||
line-height: 26px;
|
||||
}
|
||||
.agreement {
|
||||
color: #04498c;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.checkbox-box ::v-deep .uni-checkbox-input{
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
.checkbox-box ::v-deep .uni-checkbox-input.uni-checkbox-input-checked{
|
||||
border-color: $uni-color-primary;
|
||||
color: #FFFFFF !important;
|
||||
background-color: $uni-color-primary;
|
||||
}
|
||||
|
||||
.content{
|
||||
flex-wrap: wrap;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.root ::v-deep .uni-popup__error{
|
||||
color: #333333;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,198 @@
|
||||
<template>
|
||||
<button open-type="chooseAvatar" @chooseavatar="bindchooseavatar" @click="uploadAvatarImg" class="box" :class="{'showBorder':border}" :style="{width,height,lineHeight:height}">
|
||||
<cloud-image v-if="avatar_file" :src="avatar_file.url" :width="width" :height="height"></cloud-image>
|
||||
<uni-icons v-else :style="{width,height,lineHeight:height}" class="chooseAvatar" type="plusempty" size="30"
|
||||
color="#dddddd"></uni-icons>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
store,
|
||||
mutations
|
||||
} from '@/uni_modules/uni-id-pages/common/store.js'
|
||||
/**
|
||||
* uni-id-pages-avatar
|
||||
* @description 用户头像组件
|
||||
* @property {String} width 图片的宽,默认为:50px
|
||||
* @property {String} height 图片的高,默认为:50px
|
||||
*/
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
isPC: false
|
||||
}
|
||||
},
|
||||
props: {
|
||||
//头像图片宽
|
||||
width: {
|
||||
type: String,
|
||||
default () {
|
||||
return "50px"
|
||||
}
|
||||
},
|
||||
//头像图片高
|
||||
height: {
|
||||
type: String,
|
||||
default () {
|
||||
return "50px"
|
||||
}
|
||||
},
|
||||
border:{
|
||||
type: Boolean,
|
||||
default () {
|
||||
return false
|
||||
}
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
// #ifdef H5
|
||||
this.isPC = !['ios', 'android'].includes(uni.getSystemInfoSync().platform);
|
||||
// #endif
|
||||
},
|
||||
computed: {
|
||||
hasLogin() {
|
||||
return store.hasLogin
|
||||
},
|
||||
userInfo() {
|
||||
return store.userInfo
|
||||
},
|
||||
avatar_file() {
|
||||
return store.userInfo.avatar_file
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setAvatarFile(avatar_file) {
|
||||
// 使用 clientDB 提交数据
|
||||
mutations.updateUserInfo({avatar_file})
|
||||
},
|
||||
async bindchooseavatar(res){
|
||||
let avatarUrl = res.detail.avatarUrl
|
||||
let avatar_file = {
|
||||
extname: avatarUrl.split('.')[avatarUrl.split('.').length - 1],
|
||||
name:'',
|
||||
url:''
|
||||
}
|
||||
//上传到服务器
|
||||
let cloudPath = this.userInfo._id + '' + Date.now()
|
||||
avatar_file.name = cloudPath
|
||||
try{
|
||||
uni.showLoading({
|
||||
title: "更新中",
|
||||
mask: true
|
||||
});
|
||||
let {
|
||||
fileID
|
||||
} = await uniCloud.uploadFile({
|
||||
filePath:avatarUrl,
|
||||
cloudPath,
|
||||
fileType: "image"
|
||||
});
|
||||
avatar_file.url = fileID
|
||||
uni.hideLoading()
|
||||
}catch(e){
|
||||
console.error(e);
|
||||
}
|
||||
console.log('avatar_file',avatar_file);
|
||||
this.setAvatarFile(avatar_file)
|
||||
},
|
||||
uploadAvatarImg(res) {
|
||||
// #ifdef MP-WEIXIN
|
||||
return false // 微信小程序走 bindchooseavatar方法
|
||||
// #endif
|
||||
|
||||
// #ifndef MP-WEIXIN
|
||||
if(!this.hasLogin){
|
||||
return uni.navigateTo({
|
||||
url:'/uni_modules/uni-id-pages/pages/login/login-withoutpwd'
|
||||
})
|
||||
}
|
||||
const crop = {
|
||||
quality: 100,
|
||||
width: 600,
|
||||
height: 600,
|
||||
resize: true
|
||||
};
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
crop,
|
||||
success: async (res) => {
|
||||
let tempFile = res.tempFiles[0],
|
||||
avatar_file = {
|
||||
// #ifdef H5
|
||||
extname: tempFile.name.split('.')[tempFile.name.split('.').length - 1],
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
extname: tempFile.path.split('.')[tempFile.path.split('.').length - 1]
|
||||
// #endif
|
||||
},
|
||||
filePath = res.tempFilePaths[0]
|
||||
|
||||
//非app端剪裁头像,app端用内置的原生裁剪
|
||||
// #ifdef H5
|
||||
if (!this.isPC) {
|
||||
filePath = await new Promise((callback) => {
|
||||
uni.navigateTo({
|
||||
url: '/uni_modules/uni-id-pages/pages/userinfo/cropImage/cropImage?path=' +
|
||||
filePath + `&options=${JSON.stringify(crop)}`,
|
||||
animationType: "fade-in",
|
||||
events: {
|
||||
success: url => {
|
||||
callback(url)
|
||||
}
|
||||
},
|
||||
complete(e) {
|
||||
console.log(e);
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
// #endif
|
||||
|
||||
let cloudPath = this.userInfo._id + '' + Date.now()
|
||||
avatar_file.name = cloudPath
|
||||
uni.showLoading({
|
||||
title: "更新中",
|
||||
mask: true
|
||||
});
|
||||
let {
|
||||
fileID
|
||||
} = await uniCloud.uploadFile({
|
||||
filePath,
|
||||
cloudPath,
|
||||
fileType: "image"
|
||||
});
|
||||
avatar_file.url = fileID
|
||||
uni.hideLoading()
|
||||
this.setAvatarFile(avatar_file)
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* #ifndef APP-NVUE */
|
||||
.box{
|
||||
overflow: hidden;
|
||||
}
|
||||
/* #endif */
|
||||
.box{
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.chooseAvatar {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
/* #endif */
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
padding: 1px;
|
||||
}
|
||||
.showBorder{
|
||||
border: solid 1px #ddd;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,160 @@
|
||||
<template>
|
||||
<uni-popup ref="popup" type="bottom">
|
||||
<view class="box">
|
||||
<text class="headBox">绑定资料</text>
|
||||
<text class="tip">将一键获取你的手机号码绑定你的个人资料</text>
|
||||
<view class="btnBox">
|
||||
<text @click="closeMe" class="close">关闭</text>
|
||||
<button class="agree uni-btn" type="primary" open-type="getPhoneNumber"
|
||||
@getphonenumber="bindMobileByMpWeixin">获取</button>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const db = uniCloud.database();
|
||||
const usersTable = db.collection('uni-id-users')
|
||||
const uniIdCo = uniCloud.importObject("uni-id-co")
|
||||
export default {
|
||||
emits: ['success'],
|
||||
computed: {},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
methods: {
|
||||
async beforeGetphonenumber() {
|
||||
return await new Promise((resolve,reject)=>{
|
||||
uni.showLoading({ mask: true })
|
||||
wx.checkSession({
|
||||
success() {
|
||||
// console.log('session_key 未过期');
|
||||
resolve()
|
||||
uni.hideLoading()
|
||||
},
|
||||
fail() {
|
||||
// console.log('session_key 已经失效,正在执行更新');
|
||||
wx.login({
|
||||
success({
|
||||
code
|
||||
}) {
|
||||
uniCloud.importObject("uni-id-co",{
|
||||
customUI:true
|
||||
}).loginByWeixin({code}).then(e=>{
|
||||
resolve()
|
||||
}).catch(e=>{
|
||||
console.log(e);
|
||||
reject()
|
||||
}).finally(e=>{
|
||||
uni.hideLoading()
|
||||
})
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error(err);
|
||||
reject()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
async bindMobileByMpWeixin(e) {
|
||||
if (e.detail.errMsg == "getPhoneNumber:ok") {
|
||||
//检查登录信息是否过期,否则通过重新登录刷新session_key
|
||||
await this.beforeGetphonenumber()
|
||||
uniIdCo.bindMobileByMpWeixin(e.detail).then(e => {
|
||||
this.$emit('success')
|
||||
}).finally(e => {
|
||||
this.closeMe()
|
||||
})
|
||||
} else {
|
||||
this.closeMe()
|
||||
}
|
||||
},
|
||||
async open() {
|
||||
this.$refs.popup.open()
|
||||
},
|
||||
closeMe(e) {
|
||||
this.$refs.popup.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/uni_modules/uni-id-pages/common/login-page.scss";
|
||||
view {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.box {
|
||||
background-color: #FFFFFF;
|
||||
height: 200px;
|
||||
width: 750rpx;
|
||||
flex-direction: column;
|
||||
border-top-left-radius: 15px;
|
||||
border-top-right-radius: 15px;
|
||||
}
|
||||
|
||||
.headBox {
|
||||
padding: 20rpx;
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
text-align: left;
|
||||
font-size: 16px;
|
||||
color: #333333;
|
||||
margin-left: 15rpx;
|
||||
}
|
||||
|
||||
.tip {
|
||||
color: #666666;
|
||||
text-align: left;
|
||||
justify-content: center;
|
||||
margin: 10rpx 30rpx;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.btnBox {
|
||||
margin-top: 45rpx;
|
||||
justify-content: center;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.close,
|
||||
.agree {
|
||||
text-align: center;
|
||||
width: 200rpx;
|
||||
height: 80upx;
|
||||
line-height: 80upx;
|
||||
border-radius: 5px;
|
||||
margin: 0 20rpx;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.close {
|
||||
color: #999999;
|
||||
border-color: #EEEEEE;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
.close:active {
|
||||
color: #989898;
|
||||
background-color: #E2E2E2;
|
||||
}
|
||||
|
||||
.agree {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
/* #ifdef MP */
|
||||
.agree::after {
|
||||
border: none;
|
||||
}
|
||||
/* #endif */
|
||||
|
||||
.agree:active {
|
||||
background-color: #F5F5F6;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,248 @@
|
||||
<template>
|
||||
<view>
|
||||
<uni-captcha :focus="focusCaptchaInput" ref="captcha" scene="send-email-code" v-model="captcha" />
|
||||
<view class="box">
|
||||
<uni-easyinput :focus="focusEmailCodeInput" @blur="focusEmailCodeInput = false" type="number" class="input-box" :inputBorder="false" v-model="modelValue" maxlength="6"
|
||||
placeholder="请输入邮箱验证码">
|
||||
</uni-easyinput>
|
||||
<view class="short-code-btn" hover-class="hover" @click="start">
|
||||
<text class="inner-text" :class="reverseNumber==0?'inner-text-active':''">{{innerText}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
function debounce(func, wait) {
|
||||
let timer;
|
||||
wait = wait || 500;
|
||||
return function() {
|
||||
let context = this;
|
||||
let args = arguments;
|
||||
if (timer) clearTimeout(timer);
|
||||
let callNow = !timer;
|
||||
timer = setTimeout(() => {
|
||||
timer = null;
|
||||
}, wait)
|
||||
if (callNow) func.apply(context, args);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* email-code-form
|
||||
* @description 获取邮箱验证码组件
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=
|
||||
* @property {Number} count 倒计时时长 s
|
||||
* @property {String} email 邮箱
|
||||
* @property {String} type = [login-by-email-code|reset-pwd-by-email-code|bind-email] 验证码类型,用于防止不同功能的验证码混用,目前支持的类型login登录、register注册、bind绑定邮箱、unbind解绑邮箱
|
||||
* @property {false} focusCaptchaInput = [true|false] 验证码输入框是否默认获取焦点
|
||||
*/
|
||||
export default {
|
||||
name: "uni-email-code-form",
|
||||
model: {
|
||||
prop: 'modelValue',
|
||||
event: 'update:modelValue'
|
||||
},
|
||||
props: {
|
||||
event: ['update:modelValue'],
|
||||
/**
|
||||
* 倒计时时长 s
|
||||
*/
|
||||
count: {
|
||||
type: [String, Number],
|
||||
default: 60
|
||||
},
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
email: {
|
||||
type: [String],
|
||||
default: ''
|
||||
},
|
||||
/*
|
||||
验证码类型,用于防止不同功能的验证码混用,目前支持的类型login登录、register注册、bind绑定邮箱、unbind解绑邮箱
|
||||
*/
|
||||
type: {
|
||||
type: String,
|
||||
default () {
|
||||
return 'register'
|
||||
}
|
||||
},
|
||||
/*
|
||||
验证码输入框是否默认获取焦点
|
||||
*/
|
||||
focusCaptchaInput: {
|
||||
type: Boolean,
|
||||
default () {
|
||||
return false
|
||||
}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
captcha: "",
|
||||
reverseNumber: 0,
|
||||
reverseTimer: null,
|
||||
modelValue: "",
|
||||
focusEmailCodeInput:false
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
captcha(value, oldValue) {
|
||||
if (value.length == 4 && oldValue.length != 4) {
|
||||
this.start()
|
||||
}
|
||||
},
|
||||
modelValue(value) {
|
||||
// TODO 兼容 vue2
|
||||
this.$emit('input', value);
|
||||
// TODO 兼容 vue3
|
||||
this.$emit('update:modelValue', value)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
innerText() {
|
||||
if (this.reverseNumber == 0) return "获取邮箱验证码";
|
||||
return "重新发送" + '(' + this.reverseNumber + 's)';
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.initClick();
|
||||
},
|
||||
methods: {
|
||||
getImageCaptcha(focus) {
|
||||
this.$refs.captcha.getImageCaptcha(focus)
|
||||
},
|
||||
initClick() {
|
||||
this.start = debounce(() => {
|
||||
if (this.reverseNumber != 0) return;
|
||||
this.sendMsg();
|
||||
})
|
||||
},
|
||||
sendMsg() {
|
||||
if (this.captcha.length != 4) {
|
||||
this.$refs.captcha.focusCaptchaInput = true
|
||||
return uni.showToast({
|
||||
title: '请先输入图形验证码',
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
}
|
||||
if(!this.email) return uni.showToast({
|
||||
title: "请输入邮箱",
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
let reg_email = /@/;
|
||||
if (!reg_email.test(this.email)) return uni.showToast({
|
||||
title: "邮箱格式错误",
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
const uniIdCo = uniCloud.importObject("uni-id-co", {
|
||||
customUI: true
|
||||
})
|
||||
console.log('sendEmailCode',{
|
||||
"email": this.email,
|
||||
"scene": this.type,
|
||||
"captcha": this.captcha
|
||||
});
|
||||
uniIdCo.sendEmailCode({
|
||||
"email": this.email,
|
||||
"scene": this.type,
|
||||
"captcha": this.captcha
|
||||
}).then(result => {
|
||||
uni.showToast({
|
||||
title: "邮箱验证码发送成功",
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
this.reverseNumber = Number(this.count);
|
||||
this.getCode();
|
||||
}).catch(e => {
|
||||
if (e.code == "uni-id-invalid-mail-template") {
|
||||
this.modelValue = "123456"
|
||||
uni.showToast({
|
||||
title: '已启动测试模式,详情【控制台信息】',
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
console.warn(e.message);
|
||||
} else {
|
||||
this.getImageCaptcha()
|
||||
this.captcha = ""
|
||||
uni.showToast({
|
||||
title: e.message,
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
getCode() {
|
||||
if (this.reverseNumber == 0) {
|
||||
clearTimeout(this.reverseTimer);
|
||||
this.reverseTimer = null;
|
||||
return;
|
||||
}
|
||||
this.reverseNumber--;
|
||||
this.reverseTimer = setTimeout(() => {
|
||||
this.getCode();
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.box {
|
||||
position: relative;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.short-code-btn {
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 8px;
|
||||
width: 260rpx;
|
||||
max-width: 130px;
|
||||
height: 44px;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
}
|
||||
|
||||
.inner-text {
|
||||
font-size: 14px;
|
||||
color: #AAAAAA;
|
||||
}
|
||||
|
||||
.inner-text-active {
|
||||
color: #04498c;
|
||||
}
|
||||
|
||||
.captcha {
|
||||
width: 350rpx;
|
||||
}
|
||||
|
||||
.input-box {
|
||||
margin: 0;
|
||||
padding: 4px;
|
||||
background-color: #F8F8F8;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.box ::v-deep .content-clear-icon {
|
||||
margin-right: 100px;
|
||||
}
|
||||
|
||||
.box {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,568 @@
|
||||
<template>
|
||||
<view>
|
||||
<view class="fab-login-box">
|
||||
<view class="item" v-for="(item,index) in servicesList" :key="index"
|
||||
@click="item.path?toPage(item.path):login_before(item.id,false)">
|
||||
<image class="logo" :src="item.logo" mode="scaleToFill"></image>
|
||||
<text class="login-title">{{item.text}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import config from '@/uni_modules/uni-id-pages/config.js'
|
||||
//前一个窗口的页面地址。控制点击切换快捷登录方式是创建还是返回
|
||||
import {store,mutations} from '@/uni_modules/uni-id-pages/common/store.js'
|
||||
let allServicesList = []
|
||||
export default {
|
||||
computed: {
|
||||
agreements() {
|
||||
if (!config.agreements) {
|
||||
return []
|
||||
}
|
||||
let {
|
||||
serviceUrl,
|
||||
privacyUrl
|
||||
} = config.agreements
|
||||
return [{
|
||||
url: serviceUrl,
|
||||
title: "用户服务协议"
|
||||
},
|
||||
{
|
||||
url: privacyUrl,
|
||||
title: "隐私政策条款"
|
||||
}
|
||||
]
|
||||
},
|
||||
agree: {
|
||||
get() {
|
||||
return this.getParentComponent().agree
|
||||
},
|
||||
set(agree) {
|
||||
return this.getParentComponent().agree = agree
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
servicesList: [{
|
||||
"id": "username",
|
||||
"text": "账号登录",
|
||||
"logo": "/uni_modules/uni-id-pages/static/login/uni-fab-login/user.png",
|
||||
"path": "/uni_modules/uni-id-pages/pages/login/login-withpwd"
|
||||
},
|
||||
{
|
||||
"id": "smsCode",
|
||||
"text": "短信验证码",
|
||||
"logo": "/uni_modules/uni-id-pages/static/login/uni-fab-login/sms.png",
|
||||
"path": "/uni_modules/uni-id-pages/pages/login/login-withoutpwd?type=smsCode"
|
||||
},
|
||||
{
|
||||
"id": "weixin",
|
||||
"text": "微信登录",
|
||||
"logo": "/uni_modules/uni-id-pages/static/login/uni-fab-login/weixin.png",
|
||||
},
|
||||
// #ifndef MP-WEIXIN
|
||||
{
|
||||
"id": "apple",
|
||||
"text": "苹果登录",
|
||||
"logo": "/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/apple.png",
|
||||
},
|
||||
{
|
||||
"id": "univerify",
|
||||
"text": "一键登录",
|
||||
"logo": "/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/univerify.png",
|
||||
},
|
||||
{
|
||||
"id": "taobao",
|
||||
"text": "淘宝登录", //暂未提供该登录方式的接口示例
|
||||
"logo": "/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/taobao.png",
|
||||
},
|
||||
{
|
||||
"id": "facebook",
|
||||
"text": "脸书登录", //暂未提供该登录方式的接口示例
|
||||
"logo": "/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/facebook.png",
|
||||
},
|
||||
{
|
||||
"id": "alipay",
|
||||
"text": "支付宝登录", //暂未提供该登录方式的接口示例
|
||||
"logo": "/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/alipay.png",
|
||||
},
|
||||
{
|
||||
"id": "qq",
|
||||
"text": "QQ登录", //暂未提供该登录方式的接口示例
|
||||
"logo": "/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/qq.png",
|
||||
},
|
||||
{
|
||||
"id": "google",
|
||||
"text": "谷歌登录", //暂未提供该登录方式的接口示例
|
||||
"logo": "/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/google.png",
|
||||
},
|
||||
{
|
||||
"id": "douyin",
|
||||
"text": "抖音登录", //暂未提供该登录方式的接口示例
|
||||
"logo": "/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/douyin.png",
|
||||
},
|
||||
{
|
||||
"id": "sinaweibo",
|
||||
"text": "新浪微博", //暂未提供该登录方式的接口示例
|
||||
"logo": "/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/sinaweibo.png",
|
||||
}
|
||||
// #endif
|
||||
],
|
||||
univerifyStyle: { //一键登录弹出窗的样式配置参数
|
||||
"fullScreen": true, // 是否全屏显示,true表示全屏模式,false表示非全屏模式,默认值为false。
|
||||
"backgroundColor": "#ffffff", // 授权页面背景颜色,默认值:#ffffff
|
||||
"buttons": { // 自定义登录按钮
|
||||
"iconWidth": "45px", // 图标宽度(高度等比例缩放) 默认值:45px
|
||||
"list": []
|
||||
},
|
||||
"privacyTerms": {
|
||||
"defaultCheckBoxState": false, // 条款勾选框初始状态 默认值: true
|
||||
"textColor": "#BBBBBB", // 文字颜色 默认值:#BBBBBB
|
||||
"termsColor": "#5496E3", // 协议文字颜色 默认值: #5496E3
|
||||
"prefix": "我已阅读并同意", // 条款前的文案 默认值:“我已阅读并同意”
|
||||
"suffix": "并使用本机号码登录", // 条款后的文案 默认值:“并使用本机号码登录”
|
||||
"privacyItems": []
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
agree(agree) {
|
||||
this.univerifyStyle.privacyTerms.defaultCheckBoxState = agree
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
let servicesList = this.servicesList
|
||||
let loginTypes = config.loginTypes
|
||||
|
||||
servicesList = servicesList.filter(item => {
|
||||
|
||||
// #ifndef APP
|
||||
//非app端去掉apple登录
|
||||
if (item.id == 'apple') {
|
||||
return false
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifdef APP
|
||||
//去掉非ios系统上的apple登录
|
||||
if (item.id == 'apple' && uni.getSystemInfoSync().osName != 'ios') {
|
||||
return false
|
||||
}
|
||||
// #endif
|
||||
|
||||
return loginTypes.includes(item.id)
|
||||
})
|
||||
//处理一键登录
|
||||
if (loginTypes.includes('univerify')) {
|
||||
this.univerifyStyle.privacyTerms.privacyItems = this.agreements
|
||||
//设置一键登录功能底下的快捷登录按钮
|
||||
servicesList.forEach(({
|
||||
id,
|
||||
logo,
|
||||
path
|
||||
}) => {
|
||||
if (id != 'univerify') {
|
||||
this.univerifyStyle.buttons.list.push({
|
||||
"iconPath": logo,
|
||||
"provider": id,
|
||||
path //路径用于点击快捷按钮时判断是跳转页面
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
// console.log(servicesList);
|
||||
|
||||
//去掉当前页面对应的登录选项
|
||||
this.servicesList = servicesList.filter(item => {
|
||||
let path = item.path ? item.path.split('?')[0] : '';
|
||||
return path != this.getRoute(1)
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
getParentComponent(){
|
||||
// #ifndef H5
|
||||
return this.$parent;
|
||||
// #endif
|
||||
|
||||
// #ifdef H5
|
||||
return this.$parent.$parent;
|
||||
// #endif
|
||||
},
|
||||
setUserInfo(e) {
|
||||
console.log('setUserInfo', e);
|
||||
},
|
||||
getRoute(n = 0) {
|
||||
let pages = getCurrentPages();
|
||||
if (n > pages.length) {
|
||||
return ''
|
||||
}
|
||||
return '/' + pages[pages.length - n].route
|
||||
},
|
||||
toPage(path,index = 0) {
|
||||
//console.log('比较', this.getRoute(1),this.getRoute(2), path)
|
||||
if (this.getRoute(1) == path.split('?')[0] && this.getRoute(1) ==
|
||||
'/uni_modules/uni-id-pages/pages/login/login-withoutpwd') {
|
||||
//如果要被打开的页面已经打开,且这个页面是 /uni_modules/uni-id-pages/pages/index/index 则把类型参数传给他
|
||||
let loginType = path.split('?')[1].split('=')[1]
|
||||
uni.$emit('uni-id-pages-setLoginType', loginType)
|
||||
} else if (this.getRoute(2) == path) { // 如果上一个页面就是,马上要打开的页面,直接返回。防止重复开启
|
||||
uni.navigateBack();
|
||||
} else if (this.getRoute(1) != path) {
|
||||
if(index === 0){
|
||||
uni.navigateTo({
|
||||
url: path,
|
||||
animationType: 'slide-in-left',
|
||||
complete(e) {
|
||||
// console.log(e);
|
||||
}
|
||||
})
|
||||
}else{
|
||||
uni.redirectTo({
|
||||
url: path,
|
||||
animationType: 'slide-in-left',
|
||||
complete(e) {
|
||||
// console.log(e);
|
||||
}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
console.log('出乎意料的情况,path:' + path);
|
||||
}
|
||||
},
|
||||
async login_before(type, navigateBack = true, options = {}) {
|
||||
console.log(type);
|
||||
//提示空实现
|
||||
if (["qq",
|
||||
"xiaomi",
|
||||
"sinaweibo",
|
||||
"taobao",
|
||||
"facebook",
|
||||
"google",
|
||||
"alipay",
|
||||
"douyin",
|
||||
].includes(type)) {
|
||||
return uni.showToast({
|
||||
title: '该登录方式暂未实现,欢迎提交pr',
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
}
|
||||
|
||||
//检查当前环境是否支持这种登录方式
|
||||
// #ifdef APP
|
||||
let isAppExist = true
|
||||
await new Promise((callback) => {
|
||||
plus.oauth.getServices(oauthServices => {
|
||||
let index = oauthServices.findIndex(e => e.id == type)
|
||||
if(index != -1){
|
||||
isAppExist = oauthServices[index].nativeClient
|
||||
callback()
|
||||
}else{
|
||||
return uni.showToast({
|
||||
title: '当前设备不支持此登录,请选择其他登录方式',
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
}
|
||||
}, err => {
|
||||
throw new Error('获取服务供应商失败:' + JSON.stringify(err))
|
||||
})
|
||||
})
|
||||
// #endif
|
||||
|
||||
if (
|
||||
// #ifdef APP
|
||||
!isAppExist
|
||||
// #endif
|
||||
|
||||
//非app端使用了,app特有登录方式
|
||||
// #ifndef APP
|
||||
["univerify","apple"].includes(type)
|
||||
// #endif
|
||||
|
||||
) {
|
||||
return uni.showToast({
|
||||
title: '当前设备不支持此登录,请选择其他登录方式',
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
}
|
||||
|
||||
//判断是否需要弹出隐私协议授权框
|
||||
let needAgreements = (config?.agreements?.scope || []).includes('register')
|
||||
if (type != 'univerify' && needAgreements && !this.agree) {
|
||||
let agreementsRef = this.getParentComponent().$refs.agreements
|
||||
return agreementsRef.popup(() => {
|
||||
this.login_before(type, navigateBack, options)
|
||||
})
|
||||
}
|
||||
|
||||
// #ifdef H5
|
||||
if(type == 'weixin'){
|
||||
// console.log('开始微信网页登录');
|
||||
// let redirectUrl = location.protocol +'//'+
|
||||
// document.domain +
|
||||
// (window.location.href.includes('#')?'/#':'') +
|
||||
// '/uni_modules/uni-id-pages/pages/login/login-withoutpwd?is_weixin_redirect=true&type=weixin'
|
||||
// #ifdef VUE2
|
||||
const baseUrl = process.env.BASE_URL
|
||||
// #endif
|
||||
// #ifdef VUE3
|
||||
const baseUrl = import.meta.env.BASE_URL
|
||||
// #endif
|
||||
|
||||
let redirectUrl = location.protocol +
|
||||
'//' +
|
||||
location.host +
|
||||
baseUrl.replace(/\/$/, '') +
|
||||
(window.location.href.includes('#')?'/#':'') +
|
||||
'/uni_modules/uni-id-pages/pages/login/login-withoutpwd?is_weixin_redirect=true&type=weixin'
|
||||
|
||||
// console.log('redirectUrl----',redirectUrl);
|
||||
let ua = window.navigator.userAgent.toLowerCase();
|
||||
if (ua.match(/MicroMessenger/i) == 'micromessenger'){
|
||||
// console.log('在微信公众号内');
|
||||
return window.open(`https://open.weixin.qq.com/connect/oauth2/authorize?
|
||||
appid=${config.appid.weixin.h5}
|
||||
&redirect_uri=${encodeURIComponent(redirectUrl)}
|
||||
&response_type=code
|
||||
&scope=snsapi_userinfo
|
||||
&state=STATE&connect_redirect=1#wechat_redirect`);
|
||||
|
||||
}else{
|
||||
// console.log('非微信公众号内');
|
||||
return location.href = `https://open.weixin.qq.com/connect/qrconnect?appid=${config.appid.weixin.web}
|
||||
&redirect_uri=${encodeURIComponent(redirectUrl)}
|
||||
&response_type=code&scope=snsapi_login&state=STATE#wechat_redirect`
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
|
||||
uni.showLoading({
|
||||
mask: true
|
||||
})
|
||||
|
||||
if (type == 'univerify') {
|
||||
let univerifyManager = uni.getUniverifyManager()
|
||||
let clickAnotherButtons = false
|
||||
let onButtonsClickFn = async res => {
|
||||
console.log('点击了第三方登录,provider:', res, res.provider, this.univerifyStyle.buttons.list);
|
||||
clickAnotherButtons = true
|
||||
let checkBoxState = await uni.getCheckBoxState();
|
||||
// 同步一键登录弹出层隐私协议框是否打勾
|
||||
// #ifdef VUE2
|
||||
this.agree = checkBoxState[1].state
|
||||
// #endif
|
||||
// #ifdef VUE3
|
||||
this.agree = checkBoxState.state
|
||||
// #endif
|
||||
let {
|
||||
path
|
||||
} = this.univerifyStyle.buttons.list[res.index]
|
||||
if (path) {
|
||||
if( this.getRoute(1).includes('login-withoutpwd') && path.includes('login-withoutpwd') ){
|
||||
this.getParentComponent().showCurrentWebview()
|
||||
}
|
||||
this.toPage(path,1)
|
||||
closeUniverify()
|
||||
} else {
|
||||
if (this.agree) {
|
||||
closeUniverify()
|
||||
setTimeout(() => {
|
||||
this.login_before(res.provider)
|
||||
}, 500)
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: "你未同意隐私政策协议",
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function closeUniverify() {
|
||||
uni.hideLoading()
|
||||
univerifyManager.close()
|
||||
// 取消订阅自定义按钮点击事件
|
||||
univerifyManager.offButtonsClick(onButtonsClickFn)
|
||||
}
|
||||
// 订阅自定义按钮点击事件
|
||||
univerifyManager.onButtonsClick(onButtonsClickFn)
|
||||
// 调用一键登录弹框
|
||||
return univerifyManager.login({
|
||||
"univerifyStyle": this.univerifyStyle,
|
||||
success: res => {
|
||||
this.login(res.authResult, 'univerify')
|
||||
},
|
||||
fail(err) {
|
||||
console.log(err)
|
||||
if(!clickAnotherButtons){
|
||||
uni.navigateBack()
|
||||
}
|
||||
// uni.showToast({
|
||||
// title: JSON.stringify(err),
|
||||
// icon: 'none',
|
||||
// duration: 3000
|
||||
// });
|
||||
},
|
||||
complete: async e => {
|
||||
uni.hideLoading()
|
||||
//同步一键登录弹出层隐私协议框是否打勾
|
||||
// this.agree = (await uni.getCheckBoxState())[1].state
|
||||
// 取消订阅自定义按钮点击事件
|
||||
univerifyManager.offButtonsClick(onButtonsClickFn)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (type === 'weixinMobile') {
|
||||
return this.login({
|
||||
phoneCode: options.phoneNumberCode
|
||||
}, type)
|
||||
}
|
||||
|
||||
uni.login({
|
||||
"provider": type,
|
||||
"onlyAuthorize": true,
|
||||
// #ifdef APP
|
||||
"univerifyStyle": this.univerifyStyle,
|
||||
// #endif
|
||||
success: async e => {
|
||||
if (type == 'apple') {
|
||||
let res = await this.getUserInfo({
|
||||
provider: "apple"
|
||||
})
|
||||
Object.assign(e.authResult, res.userInfo)
|
||||
uni.hideLoading()
|
||||
}
|
||||
this.login(type == 'weixin' ? {
|
||||
code: e.code
|
||||
} : e.authResult, type)
|
||||
},
|
||||
fail: async (err) => {
|
||||
console.log(err);
|
||||
uni.hideLoading()
|
||||
}
|
||||
})
|
||||
},
|
||||
login(params, type) { //联网验证登录
|
||||
// console.log('执行登录开始----');
|
||||
console.log({params,type});
|
||||
//toLowerCase
|
||||
let action = 'loginBy' + type.trim().replace(type[0], type[0].toUpperCase())
|
||||
const uniIdCo = uniCloud.importObject("uni-id-co",{
|
||||
customUI:true
|
||||
})
|
||||
uniIdCo[action](params).then(result => {
|
||||
uni.showToast({
|
||||
title: '登录成功',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
// #ifdef H5
|
||||
result.loginType = type
|
||||
// #endif
|
||||
mutations.loginSuccess(result)
|
||||
})
|
||||
.catch(e=>{
|
||||
uni.showModal({
|
||||
content: e.message,
|
||||
confirmText:"知道了",
|
||||
showCancel: false
|
||||
});
|
||||
})
|
||||
.finally(e => {
|
||||
if (type == 'univerify') {
|
||||
uni.closeAuthView()
|
||||
}
|
||||
uni.hideLoading()
|
||||
})
|
||||
},
|
||||
async getUserInfo(e) {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.getUserInfo({
|
||||
...e,
|
||||
success: (res) => {
|
||||
resolve(res);
|
||||
},
|
||||
fail: (err) => {
|
||||
uni.showModal({
|
||||
content: JSON.stringify(err),
|
||||
showCancel: false
|
||||
});
|
||||
reject(err);
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
/* #ifndef APP-NVUE */
|
||||
.fab-login-box,
|
||||
.item {
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
flex-direction: column;
|
||||
}
|
||||
/* #endif */
|
||||
|
||||
.fab-login-box {
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
width: 750rpx;
|
||||
justify-content: space-around;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.item {
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 200rpx;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* #ifndef APP-NVUE */
|
||||
@media screen and (min-width: 690px) {
|
||||
.fab-login-box {
|
||||
max-width: 500px;
|
||||
margin-left: calc(50% - 250px);
|
||||
}
|
||||
.item {
|
||||
height: 160rpx;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 690px) {
|
||||
.fab-login-box {
|
||||
bottom: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
|
||||
.logo {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
max-width: 40px;
|
||||
max-height: 40px;
|
||||
border-radius: 100%;
|
||||
border: solid 1px #F6F6F6;
|
||||
}
|
||||
|
||||
.login-title {
|
||||
text-align: center;
|
||||
margin-top: 6px;
|
||||
color: #999;
|
||||
font-size: 10px;
|
||||
width: 70px;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,242 @@
|
||||
<template>
|
||||
<view>
|
||||
<uni-captcha :focus="focusCaptchaInput" ref="captcha" scene="send-sms-code" v-model="captcha" />
|
||||
<view class="box">
|
||||
<uni-easyinput :focus="focusSmsCodeInput" @blur="focusSmsCodeInput = false" type="number" class="input-box" :inputBorder="false" v-model="modelValue" maxlength="6" :clearable="false"
|
||||
placeholder="请输入短信验证码">
|
||||
</uni-easyinput>
|
||||
<view class="short-code-btn" hover-class="hover" @click="start">
|
||||
<text class="inner-text" :class="reverseNumber==0?'inner-text-active':''">{{innerText}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
function debounce(func, wait) {
|
||||
let timer;
|
||||
wait = wait || 500;
|
||||
return function() {
|
||||
let context = this;
|
||||
let args = arguments;
|
||||
if (timer) clearTimeout(timer);
|
||||
let callNow = !timer;
|
||||
timer = setTimeout(() => {
|
||||
timer = null;
|
||||
}, wait)
|
||||
if (callNow) func.apply(context, args);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* sms-form
|
||||
* @description 获取短信验证码组件
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=
|
||||
* @property {Number} count 倒计时时长 s
|
||||
* @property {String} phone 手机号码
|
||||
* @property {String} type = [login-by-sms|reset-pwd-by-sms|bind-mobile] 验证码类型,用于防止不同功能的验证码混用,目前支持的类型login登录、register注册、bind绑定手机、unbind解绑手机
|
||||
* @property {false} focusCaptchaInput = [true|false] 验证码输入框是否默认获取焦点
|
||||
*/
|
||||
export default {
|
||||
name: "uni-sms-form",
|
||||
model: {
|
||||
prop: 'modelValue',
|
||||
event: 'update:modelValue'
|
||||
},
|
||||
props: {
|
||||
event: ['update:modelValue'],
|
||||
/**
|
||||
* 倒计时时长 s
|
||||
*/
|
||||
count: {
|
||||
type: [String, Number],
|
||||
default: 60
|
||||
},
|
||||
/**
|
||||
* 手机号码
|
||||
*/
|
||||
phone: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
/*
|
||||
验证码类型,用于防止不同功能的验证码混用,目前支持的类型login登录、register注册、bind绑定手机、unbind解绑手机
|
||||
*/
|
||||
type: {
|
||||
type: String,
|
||||
default () {
|
||||
return 'login'
|
||||
}
|
||||
},
|
||||
/*
|
||||
验证码输入框是否默认获取焦点
|
||||
*/
|
||||
focusCaptchaInput: {
|
||||
type: Boolean,
|
||||
default () {
|
||||
return false
|
||||
}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
captcha: "",
|
||||
reverseNumber: 0,
|
||||
reverseTimer: null,
|
||||
modelValue: "",
|
||||
focusSmsCodeInput:false
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
captcha(value, oldValue) {
|
||||
if (value.length == 4 && oldValue.length != 4) {
|
||||
this.start()
|
||||
}
|
||||
},
|
||||
modelValue(value) {
|
||||
// TODO 兼容 vue2
|
||||
this.$emit('input', value);
|
||||
// TODO 兼容 vue3
|
||||
this.$emit('update:modelValue', value)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
innerText() {
|
||||
if (this.reverseNumber == 0) return "获取短信验证码";
|
||||
return "重新发送" + '(' + this.reverseNumber + 's)';
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.initClick();
|
||||
},
|
||||
methods: {
|
||||
getImageCaptcha(focus) {
|
||||
this.$refs.captcha.getImageCaptcha(focus)
|
||||
},
|
||||
initClick() {
|
||||
this.start = debounce(() => {
|
||||
if (this.reverseNumber != 0) return;
|
||||
this.sendMsg();
|
||||
})
|
||||
},
|
||||
sendMsg() {
|
||||
if (this.captcha.length != 4) {
|
||||
this.$refs.captcha.focusCaptchaInput = true
|
||||
return uni.showToast({
|
||||
title: '请先输入图形验证码',
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
}
|
||||
let reg_phone = /^1\d{10}$/;
|
||||
if (!reg_phone.test(this.phone)) return uni.showToast({
|
||||
title: "手机号格式错误",
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
const uniIdCo = uniCloud.importObject("uni-id-co", {
|
||||
customUI: true
|
||||
})
|
||||
console.log('sendSmsCode',{
|
||||
"mobile": this.phone,
|
||||
"scene": this.type,
|
||||
"captcha": this.captcha
|
||||
});
|
||||
uniIdCo.sendSmsCode({
|
||||
"mobile": this.phone,
|
||||
"scene": this.type,
|
||||
"captcha": this.captcha
|
||||
}).then(result => {
|
||||
uni.showToast({
|
||||
title: "短信验证码发送成功",
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
this.reverseNumber = Number(this.count);
|
||||
this.getCode();
|
||||
}).catch(e => {
|
||||
if (e.code == "uni-id-invalid-sms-template-id") {
|
||||
this.modelValue = "123456"
|
||||
uni.showToast({
|
||||
title: '已启动测试模式,详情【控制台信息】',
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
console.warn(e.message);
|
||||
} else {
|
||||
this.getImageCaptcha()
|
||||
this.captcha = ""
|
||||
uni.showToast({
|
||||
title: e.message,
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
getCode() {
|
||||
if (this.reverseNumber == 0) {
|
||||
clearTimeout(this.reverseTimer);
|
||||
this.reverseTimer = null;
|
||||
return;
|
||||
}
|
||||
this.reverseNumber--;
|
||||
this.reverseTimer = setTimeout(() => {
|
||||
this.getCode();
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.box {
|
||||
position: relative;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.short-code-btn {
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 8px;
|
||||
width: 260rpx;
|
||||
max-width: 100px;
|
||||
height: 44px;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.inner-text {
|
||||
font-size: 14px;
|
||||
color: #AAAAAA;
|
||||
}
|
||||
|
||||
.inner-text-active {
|
||||
color: #04498c;
|
||||
}
|
||||
|
||||
.captcha {
|
||||
width: 350rpx;
|
||||
}
|
||||
|
||||
.input-box {
|
||||
margin: 0;
|
||||
padding: 4px;
|
||||
background-color: #F8F8F8;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.box ::v-deep .content-clear-icon {
|
||||
margin-right: 110px;
|
||||
}
|
||||
|
||||
.box {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,171 @@
|
||||
<template>
|
||||
<uni-popup ref="popup" type="bottom">
|
||||
<view class="box">
|
||||
<text class="headBox">绑定资料</text>
|
||||
<text class="tip">获取你的微信头像和昵称,完善你的个人资料</text>
|
||||
<view class="btnBox">
|
||||
<text @click="closeMe" class="close">关闭</text>
|
||||
<button class="agree uni-btn" type="primary" @click="getUserProfile">确定</button>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const db = uniCloud.database();
|
||||
const usersTable = db.collection('uni-id-users')
|
||||
let userId = ''
|
||||
export default {
|
||||
emits:['next'],
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
methods: {
|
||||
async open(uid){
|
||||
userId = uid
|
||||
this.$refs.popup.open()
|
||||
},
|
||||
async getUserProfile(){
|
||||
uni.showLoading();
|
||||
let res = await new Promise((callBack) => {
|
||||
uni.getUserProfile({
|
||||
desc: "用于设置账户昵称和头像",
|
||||
complete: (e) => {
|
||||
callBack(e)
|
||||
}
|
||||
})
|
||||
})
|
||||
if(res.errMsg != "getUserProfile:ok"){
|
||||
return this.closeMe()
|
||||
}
|
||||
let {avatarUrl,nickName} = res.userInfo;
|
||||
|
||||
let tempFilePath = await new Promise((callBack)=>{
|
||||
uni.downloadFile({
|
||||
url: avatarUrl,
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
// console.log('下载成功');
|
||||
callBack(res.tempFilePath)
|
||||
}
|
||||
callBack()
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error(err)
|
||||
},
|
||||
complete: (e) => {
|
||||
// console.log("downloadFile",e);
|
||||
}
|
||||
});
|
||||
})
|
||||
const extName = tempFilePath.split('.').pop() || 'jpg'
|
||||
const cloudPath = 'user/avatar/'+ userId+'/'+Date.now()+'-avatar.'+extName;
|
||||
const result = await uniCloud.uploadFile({
|
||||
filePath: tempFilePath,
|
||||
cloudPath,
|
||||
fileType:'image'
|
||||
});
|
||||
let userInfo = {
|
||||
"nickname":nickName,
|
||||
"avatar_file":{
|
||||
name:cloudPath,
|
||||
extname:"jpg",
|
||||
url:result.fileID
|
||||
}
|
||||
}
|
||||
this.doUpdate(userInfo,()=>{
|
||||
this.$refs.popup.close()
|
||||
})
|
||||
},
|
||||
closeMe(e){
|
||||
uni.showLoading();
|
||||
this.doUpdate({nickname:"匿名微信用户"},()=>{
|
||||
uni.hideLoading()
|
||||
this.$refs.popup.close()
|
||||
})
|
||||
},
|
||||
doUpdate(data,callback){
|
||||
// 使用 clientDB 提交数据
|
||||
usersTable.where('_id==$env.uid').update(data).then((res) => {
|
||||
callback(res)
|
||||
}).catch((err) => {
|
||||
uni.showModal({
|
||||
content: err.message || '请求服务失败',
|
||||
showCancel: false
|
||||
})
|
||||
callback(err)
|
||||
}).finally(() => {
|
||||
this.$emit('next')
|
||||
uni.hideLoading()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/uni_modules/uni-id-pages/common/login-page.scss";
|
||||
view{
|
||||
display: flex;
|
||||
}
|
||||
.box{
|
||||
background-color: #FFFFFF;
|
||||
height:200px;
|
||||
width: 750rpx;
|
||||
flex-direction: column;
|
||||
border-top-left-radius: 15px;
|
||||
border-top-right-radius: 15px;
|
||||
}
|
||||
.headBox{
|
||||
padding:20rpx;
|
||||
height:80rpx;
|
||||
line-height:80rpx;
|
||||
text-align: left;
|
||||
font-size:16px;
|
||||
color:#333333;
|
||||
margin-left: 15rpx;
|
||||
}
|
||||
.tip{
|
||||
color:#666666;
|
||||
text-align: left;
|
||||
justify-content: center;
|
||||
margin:10rpx 30rpx;
|
||||
font-size:18px;
|
||||
}
|
||||
.btnBox{
|
||||
margin-top:45rpx;
|
||||
justify-content: center;
|
||||
flex-direction: row;
|
||||
}
|
||||
.close,.agree{
|
||||
text-align: center;
|
||||
width:200rpx;
|
||||
height:80upx;
|
||||
line-height:80upx;
|
||||
border-radius:5px;
|
||||
margin:0 20rpx;
|
||||
font-size:14px;
|
||||
}
|
||||
.close{
|
||||
color:#999999;
|
||||
border-color: #EEEEEE;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
background-color:#FFFFFF;
|
||||
}
|
||||
.close:active{
|
||||
color:#989898;
|
||||
background-color:#E2E2E2;
|
||||
}
|
||||
.agree{
|
||||
color:#FFFFFF;
|
||||
}
|
||||
/* #ifdef MP */
|
||||
.agree::after {
|
||||
border: none;
|
||||
}
|
||||
/* #endif */
|
||||
.agree:active{
|
||||
background-color:#F5F5F6;
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user