微信登录引导头像昵称
This commit is contained in:
parent
e6a92a479b
commit
4617c65581
|
|
@ -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 })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
Loading…
Reference in New Issue