微信登录引导头像昵称

This commit is contained in:
Jason 2023-03-29 15:52:38 +08:00
parent e6a92a479b
commit 4617c65581
6 changed files with 338 additions and 22 deletions

View File

@ -26,3 +26,18 @@ export function userMnpMobile(data: any) {
export function userChangePwd(data: any) {
return request.post({ url: '/user/changePwd', data }, { isAuth: true })
}
// 绑定小程序
export function mnpAuthBind(data: any) {
return request.post({ url: '/user/bindMnp', data })
}
// 绑定公众号
export function oaAuthBind(data: any) {
return request.post({ url: '/user/bindOa', data })
}
//更新微信小程序头像昵称
export function updateUser(data: Record<string, any>, header: any) {
return request.post({ url: '/user/updateUser', data, header })
}

View File

@ -0,0 +1,107 @@
<template>
<button
class="avatar-upload p-0 m-0 rounded"
:style="styles"
hover-class="none"
open-type="chooseAvatar"
@click="chooseAvatar"
@chooseavatar="chooseAvatar"
>
<image class="w-full h-full" mode="heightFix" :src="modelValue" v-if="modelValue" />
<slot v-else>
<div
:style="styles"
class="border border-dotted border-light flex w-full h-full flex-col items-center justify-center text-muted text-xs box-border rounded"
>
<u-icon name="plus" :size="36" />
添加图片
</div>
</slot>
</button>
</template>
<script lang="ts" setup>
import { uploadImage } from '@/api/app'
import { useUserStore } from '@/stores/user'
import { addUnit } from '@/utils/util'
import { isBoolean } from 'lodash'
import { computed, CSSProperties, onUnmounted } from 'vue'
const props = defineProps({
modelValue: {
type: String
},
fileKey: {
type: String,
default: 'path'
},
size: {
type: [String, Number],
default: 120
},
round: {
type: [Boolean, String, Number],
default: false
},
border: {
type: Boolean,
default: true
}
})
const emit = defineEmits<{
(event: 'update:modelValue', value: string): void
}>()
const userStore = useUserStore()
const styles = computed<CSSProperties>(() => {
const size = addUnit(props.size)
return {
width: size,
height: size,
borderRadius: isBoolean(props.round) ? (props.round ? '50%' : '') : addUnit(props.round)
}
})
const chooseAvatar = (e: any) => {
// #ifndef MP-WEIXIN
uni.navigateTo({
url: '/uni_modules/vk-uview-ui/components/u-avatar-cropper/u-avatar-cropper?destWidth=300&rectWidth=200&fileType=jpg'
})
// #endif
// #ifdef MP-WEIXIN
const path = e.detail?.avatarUrl
if (path) {
uploadImageIng(path)
}
// #endif
}
const uploadImageIng = async (file: string) => {
uni.showLoading({
title: '正在上传中...'
})
try {
const res: any = await uploadImage(file, userStore.temToken!)
uni.hideLoading()
emit('update:modelValue', res[props.fileKey])
} catch (error) {
uni.hideLoading()
uni.$u.toast(error)
}
}
//
uni.$on('uAvatarCropper', (path) => {
uploadImageIng(path)
})
onUnmounted(() => {
uni.$off('uAvatarCropper')
})
</script>
<style lang="scss" scoped>
.avatar-upload {
background: #fff;
overflow: hidden;
&::after {
border: none;
}
}
</style>

View File

@ -0,0 +1,97 @@
<template>
<view>
<u-popup v-model="showPopup" mode="bottom" border-radius="14" :mask-close-able="false">
<view class="h-[1000rpx] p-[40rpx]">
<view class="flex items-center">
<image
class="w-[100rpx] h-[100rpx] rounded"
mode="heightFix"
:src="logo"
></image>
<text class="text-3xl ml-5 font-bold">{{ title }}</text>
</view>
<view class="mt-5 text-muted">
建议使用您的微信头像和昵称以便获得更好的体验
</view>
<view class="mt-[30rpx]">
<form @submit="handleSubmit">
<u-form-item required label="头像" :labelWidth="120">
<view class="flex-1">
<avatar-upload v-model="avatar"></avatar-upload>
</view>
</u-form-item>
<u-form-item required label="昵称" :labelWidth="120">
<input
class="flex-1 h-[60rpx]"
name="nickname"
type="nickname"
placeholder="请输入昵称"
/>
</u-form-item>
<view class="mt-[80rpx]">
<button
class="bg-primary rounded-full text-white text-lg h-[80rpx] leading-[80rpx]"
hover-class="none"
form-type="submit"
>
确定
</button>
</view>
<view class="flex justify-center mt-[60rpx]">
<view class="text-muted" @click="showPopup = false">暂不登录</view>
</view>
</form>
</view>
</view>
</u-popup>
</view>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue'
const props = defineProps({
show: {
type: Boolean
},
logo: {
type: String
},
title: {
type: String
}
})
const emit = defineEmits<{
(event: 'update:show', show: boolean): void
(event: 'update', value: any): void
}>()
const showPopup = computed({
get() {
return props.show
},
set(val) {
emit('update:show', val)
}
})
const avatar = ref()
const handleSubmit = (e: any) => {
const { nickname } = e.detail.value
if (!avatar.value)
return uni.$u.toast({
title: '请添加头像'
})
if (!nickname)
return uni.$u.toast({
title: '请输入昵称'
})
emit('update', {
avatar: avatar.value,
nickname
})
}
</script>
<style lang="scss" scoped></style>

View File

@ -154,12 +154,19 @@
</view>
<!-- #endif -->
</view>
<mplogin-popup
v-model:show="showLoginPopup"
:logo="websiteConfig.logo"
:title="websiteConfig.name"
@update="handleUpdateUser"
/>
</view>
</template>
<script setup lang="ts">
import { mobileLogin, accountLogin, mnpLogin } from '@/api/account'
import { smsSend } from '@/api/app'
import { updateUser } from '@/api/user'
import { SMSEnum } from '@/enums/appEnums'
import { BACK_URL } from '@/enums/cacheEnums'
import { useLockFn } from '@/hooks/useLockFn'
@ -187,6 +194,7 @@ enum LoginAuthEnum {
QQ = 2
}
const isWeixin = ref(true)
const showLoginPopup = ref(false)
// #ifdef H5
isWeixin.value = isWeixinClient()
// #endif
@ -194,11 +202,12 @@ isWeixin.value = isWeixinClient()
const userStore = useUserStore()
const appStore = useAppStore()
const websiteConfig = computed(() => appStore.getWebsiteConfig)
const uCodeRef = shallowRef()
const loginWay = ref<LoginWayEnum>()
const codeTips = ref('')
const isCheckAgreement = ref(false)
const loginData = ref<any>({})
const formData = reactive({
scene: '',
username: '',
@ -329,6 +338,13 @@ const { lockFn: wxLogin } = useLockFn(async () => {
const data = await mnpLogin({
code
})
loginData.value = data
if (data.isNew) {
uni.hideLoading()
userStore.temToken = data.token
showLoginPopup.value = true
return
}
loginHandle(data)
// #endif
// #ifdef H5
@ -341,6 +357,12 @@ const { lockFn: wxLogin } = useLockFn(async () => {
}
})
const handleUpdateUser = async (value: any) => {
await updateUser(value, { token: userStore.temToken })
showLoginPopup.value = false
loginHandle(loginData.value)
}
watch(
() => appStore.getLoginConfig,
(value) => {

View File

@ -20,13 +20,17 @@
<u-icon name="arrow-right" color="#666"></u-icon>
</view>
<!-- #ifdef MP-WEIXIN || H5 -->
<view class="item bg-white flex flex-1 justify-between" v-if="isWeixin">
<view
v-if="isWeixin"
class="item bg-white flex flex-1 justify-between"
@click="bindWechatLock"
>
<view class="">绑定微信</view>
<view class="flex justify-between">
<view class="text-muted mr-[20rpx]">
{{ userInfo.isBindMnp ? '已绑定' : '未绑定' }}
{{ userInfo.isBindWechat ? '已绑定' : '未绑定' }}
</view>
<!-- <u-icon name="arrow-right" color="#666"></u-icon> -->
<u-icon v-if="userInfo.isBindWechat == 0" name="arrow-right" color="#666"></u-icon>
</view>
</view>
<!-- #endif -->
@ -68,23 +72,19 @@
</template>
<script setup lang="ts">
import { getUserInfo } from '@/api/user'
import { onShow } from '@dcloudio/uni-app'
import { ref } from 'vue'
import { mnpAuthBind, oaAuthBind } from '@/api/user'
import { onLoad, onShow } from '@dcloudio/uni-app'
import { ref, computed } from 'vue'
import { useAppStore } from '@/stores/app'
import { useUserStore } from '@/stores/user'
import { AgreementEnum } from '@/enums/agreementEnums'
import { isWeixinClient } from '@/utils/client'
import wechatOa from '@/utils/wechat'
import { useLockFn } from '@/hooks/useLockFn'
const appStore = useAppStore()
const userStore = useUserStore()
const userInfo = ref({
avatar: '',
nickname: '',
username: '',
isBindMnp: '',
isPassword: ''
})
const userInfo = computed(() => userStore.userInfo)
const list = ref([
{
text: '修改密码'
@ -101,12 +101,6 @@ isWeixin.value = isWeixinClient()
const show = ref(false)
//
const getUser = async () => {
const res = await getUserInfo()
userInfo.value = res
}
// /
const handleClick = (index: number) => {
switch (index) {
@ -120,7 +114,7 @@ const handleClick = (index: number) => {
}
const handlePwd = () => {
if (!userInfo.value.isPassword)
if (!userInfo.value.hasPwd)
return uni.navigateTo({ url: '/pages/change_password/change_password?type=set' })
show.value = true
}
@ -138,8 +132,58 @@ const logoutHandle = () => {
})
}
const bindWechat = async () => {
if (userInfo.value.isBindWechat) return
try {
uni.showLoading({
title: '请稍后...'
})
// #ifdef MP-WEIXIN
const { code }: any = await uni.login({
provider: 'weixin'
})
await mnpAuthBind({
code: code
})
//#endif
// #ifdef H5
if (isWeixin.value) {
wechatOa.getUrl()
}
// #endif
uni.$u.toast('绑定成功')
await userStore.getUser()
uni.hideLoading()
} catch (e) {
uni.hideLoading()
uni.$u.toast(e)
}
}
const { lockFn: bindWechatLock } = useLockFn(bindWechat)
onShow(() => {
getUser()
userStore.getUser()
})
onLoad(async (options) => {
// #ifdef H5
const { code } = options
if (!isWeixin.value) return
if (code) {
uni.showLoading({
title: '请稍后...'
})
try {
await oaAuthBind({ code })
uni.$u.toast('绑定成功')
await userStore.getUser()
} catch (error) {}
//code
uni.redirectTo({
url: '/pages/user_set/user_set'
})
}
// #endif
})
</script>

View File

@ -93,3 +93,34 @@ export function objectToQuery(params: Record<string, any>): string {
}
return query.slice(0, -1)
}
/**
* @description
* @param { string } task
*/
export function series(...task: Array<(_arg: any) => any>) {
return function (): Promise<any> {
return new Promise((resolve, reject) => {
const iteratorTask = task.values()
const next = (res?: any) => {
const nextTask = iteratorTask.next()
if (nextTask.done) {
resolve(res)
} else {
Promise.resolve(nextTask.value(res)).then(next).catch(reject)
}
}
next()
})
}
}
/**
* @description
* @param {String | Number} value 100
* @param {String} unit px em rem
*/
export const addUnit = (value: string | number, unit = 'rpx') => {
return !Object.is(Number(value), NaN) ? `${value}${unit}` : value
}