微信小程序修改个人信息头像(uniapp开发)

news/2025/2/22 7:09:00

HTML部分

        <div class="user-img" @click="editUserImg">
            <image style="height: 128rpx;width: 128rpx;border-radius: 999px;margin-right: 10px;"
                :src="userInfo?.userImg" mode="scaleToFill" />
        </div>

TS部分

用户接口类型

interface User {
    id: number;
    userName: string;
    userImg: string;
    userPhone: string;
    userAddress: string;
    authenticated?: boolean;
}

const userInfo = ref<User>()

具体代码

//修改用户信息
const updateUserInfo = () => {
    loading.value = true
    console.log('修改用户信息', userInfo.value)
    http?.request({
        url: "api/User/updateUserInfoByOpenId",
        method: 'POST',
        data: {
            id: userInfo.value!.id,
            name: userInfo.value!.userName,
            address: userInfo.value!.userAddress,
            phone: userInfo.value!.userPhone,
            headshot: userInfo.value!.userImg,
            openId: uni.getStorageSync('openid')
        }
    }).then((res: any) => {
        if (res.code == 200) {
            uni.showToast({
                title: '修改成功!',
                icon: 'success'
            })
            getUserInfoByToken(uni.getStorageSync('openid'))
        } else {
            uni.showToast({
                title: '修改失败!',
                icon: 'error'
            })
        }
    }).catch((err: any) => {
        console.log(err)
        uni.showToast({
            title: '网络错误!',
            icon: 'error'
        })
    }).finally(() => {
        loading.value = false
    })
    editState.value = false
}

//修改用户头像
const editUserImg = () => {
    console.log('修改用户头像')
    //@ts-ignore
    wx.chooseMedia({
        count: 1,
        mediaTypes: ['image'],
        sourceType: ['album', 'camera'],
        sizeType: 'compressed',
        camera: 'front',
        success: (res: any) => {
            loading.value = true
            const { tempFiles } = res
            const tempUserImg = tempFiles[0]
            cutImgToSquare(tempUserImg.tempFilePath)
        },
        fail: (err: any) => {
            console.log("调用失败", err)
        },
        complete: (res: any) => {
            console.log("调用完成", res)
        }
    })
}

//将用户图片自动剪切成正方形
const cutImgToSquare = (imgPath: string) => {
    //@ts-ignore
    wx.createSelectorQuery()
        .select('#canvas')
        .fields({ node: true, size: true })
        .exec((res: any) => {
            const canvas = res[0].node
            const ctx = canvas.getContext('2d')
            const image = canvas.createImage()
            image.onload = () => {
                const size = Math.min(image.width, image.height)
                canvas.width = size
                canvas.height = size
                ctx.clearRect(0, 0, canvas.width, canvas.height)
                ctx.drawImage(image, (image.width - size) / 2, (image.height - size) / 2, size, size, 0, 0, size, size)
                //@ts-ignore
                wx.canvasToTempFilePath({
                    canvas,
                    success: (res: any) => {
                        console.log("调用成功", res)
                        //上传文件到服务器
                        uploadUserImg(res)
                    },
                    fail: (err: any) => {
                        console.log("调用失败", err)
                        loading.value = false
                        uni.showToast({
                            title: '图片上传失败!',
                            icon: 'error'
                        })
                    },
                    complete: (res: any) => {
                        console.log("调用完成", res)
                    }
                })
            }
            image.src = imgPath
        })
}

//将文件上传到服务器
const uploadUserImg = (file: any) => {
    //@ts-ignore
    wx.uploadFile({
        url: uploadImg,
        filePath: file.tempFilePath,
        name: 'file',
        success: (res: any) => {
            const data = JSON.parse(res.data)
            if (data.code == 200) {
                console.log("图片路径", data.data.filePath)
                userInfo.value!.userImg = data.data.filePath
                editState.value = true
            } else {
                uni.showToast({
                    title: '上传失败!',
                    icon: 'error'
                })
            }
            loading.value = false
        },
        fail: (err: any) => {
            console.log("上传失败", err)
            loading.value = false
            uni.showToast({
                title: '上传失败!',
                icon: 'error'
            })
        },
        complete: (res: any) => {
            console.log("上传完成", res)
        }
    })
}
注意:这里上传的具体服务器是我自己的服务器,这里要把uploadUserImg中的uploadImg改成自己的接口地址,不会写文件传输的可以看我之前的文章

window下的:Java基于springboot上传文件(Windows系统)-CSDN博客

Linux下的:Java基于springboot上传文件(Linux系统)-CSDN博客

完整代码

<template>
    <div class="header">
        <div class="goback" @click="goback">
            <image style="height: 3vh;" src="../../static/article/goback.png" mode="heightFix" />
        </div>
        <div class="user-img" @click="editUserImg">
            <image style="height: 128rpx;width: 128rpx;border-radius: 999px;margin-right: 10px;"
                :src="userInfo?.userImg" mode="scaleToFill" />
        </div>
    </div>
    <div class="bodyer">
        <div class="user-info">
            <view class="user-title">
                <view>
                    <image style="height: 32px;width: 32px;margin-right: 0.5em;"
                        src="../../static/userinfo/user-info-title.png" />
                </view>
                <view style="font-size: 18px;font-weight: bold;">用户信息</view>
            </view>
            <view class="user-info-box">
                <view class="user-info-item">
                    <view style="display: flex;align-items: center;">
                        <view class="decoration-blue"></view>
                        <view style="font-size: 15px;">用户名称</view>
                    </view>
                    <view class="base-info-item" v-if="!editState">{{ userInfo?.userName }}</view>
                    <view class="base-info-item" v-if="editState">
                        <input v-model="userInfo!.userName" placeholder="请输入用户名" />
                    </view>
                </view>
                <view class="user-info-item">
                    <view style="display: flex;align-items: center;">
                        <view class="decoration-blue"></view>
                        <view style="font-size: 15px;">手机号</view>
                    </view>
                    <view class="base-info-item" v-if="!editState">{{ userInfo?.userPhone == null ? '未绑定' :
                        userInfo?.userPhone }}</view>
                    <view class="base-info-item" v-if="editState">
                        <input v-model="userInfo!.userPhone" placeholder="绑定手机号" />
                    </view>
                </view>
                <view class="user-info-item">
                    <view style="display: flex;align-items: center;">
                        <view class="decoration-blue"></view>
                        <view style="font-size: 15px;">居住地址</view>
                    </view>
                    <view class="base-info-item" v-if="!editState">{{ userInfo?.userAddress == null ? '未填写' :
                        userInfo?.userAddress }}</view>
                    <view class="base-info-item" v-if="editState">
                        <input v-model="userInfo!.userAddress" placeholder="请输入居住地址" />
                    </view>
                </view>
            </view>
            <!-- <view class="authenticated">
                <view @click.stop="goAuthenticated" class="goingauthenticated" v-if="!userInfo?.authenticated">
                    <text style="font-size: 14px;margin-right: 0.5em;">去实名认证</text>
                    <image style="height: 16px;" src="../../static/seekhelp/goingseek.png" mode="heightFix" />
                </view>
            </view> -->
        </div>
    </div>
    <div class="footer">
        <view @click="editState = true" v-if="!editState">修改个人信息</view>
        <view @click="updateUserInfo" v-if="editState">保存</view>
        <view @click="logout">退出登录</view>
    </div>
    <canvas v-show="false" id="canvas" type="2d" style="position: absolute;z-index: -999;opacity: 0;" />
    <qgy-drawer ref="editAddressDrawer"></qgy-drawer>
    <div class="back2"></div>
    <qgy-loading style="position: absolute;top: 0px;left: 0px;" v-show="loading"></qgy-loading>
</template>

<script setup lang="ts">
import { Http } from '@/util/http';
import { inject, onMounted, ref } from 'vue';

const http: Http | undefined = inject('$http');
const loading = ref(false);
const uploadImg: string | undefined = inject('$uploadImg');

//修改状态
const editState = ref(false)

onMounted(() => {
    getUserInfoByToken(uni.getStorageSync('openid'))
})

//从服务器中获取用户信息
const getUserInfoByToken = (openid: string) => {
    loading.value = true
    console.log("openid", openid)
    //从后端获得用户信息
    http?.request({
        url: 'api/User/findUserInfoByOpenId?openId=' + openid,
        method: 'GET'
    }).then((res: any) => {
        console.log(res)
        if (res.code == 200) {
            userInfo.value = {
                id: res.data.id,
                userName: res.data.name,
                userAddress: res.data.address,
                userImg: res.data.headshot,
                userPhone: res.data.phone
            }
        } else {
            uni.showToast({
                title: "网络错误!",
                duration: 2000,
                icon: 'error'
            })
        }
    }).catch((err: any) => {
        console.log(err)
        uni.showToast({
            title: '网络错误!',
            duration: 2000,
            icon: 'error'
        })
    }).finally(() => {
        loading.value = false
    })
    uni.setStorageSync('token', '孩子们我们现在没有token!')
}

//退出登录
const logout = () => {
    console.log('退出登录')
    uni.clearStorageSync()
    uni.showToast({
        title: '退出成功',
        duration: 2000,
        icon: 'success'
    });
    setTimeout(() => {
        goback()
    }, 2000)
}

interface User {
    id: number;
    userName: string;
    userImg: string;
    userPhone: string;
    userAddress: string;
    authenticated?: boolean;
}

const userInfo = ref<User>()
//页面是否处于修改状态
const pageState = ref<boolean>(false)

onMounted(() => {
    //从token中获取用户信息
    userInfo.value = {
        id: 0,
        userName: '乔冠宇',
        userImg: '../../static/my/default.png',
        userPhone: '15353365292',
        userAddress: '陕西省咸阳市秦都区人民路财富中心一号楼三单元114514号',
        authenticated: false
    }
})

//返回上一页
const goback = () => {
    uni.navigateBack({
        fail: (err) => {
            console.log(err)
            uni.reLaunch({ url: '/pages/index/index' })
        }
    })
}

//去实名认证
// const goAuthenticated = () => {
//     console.log('去实名认证')
//     userInfo.value!.authenticated = true
// }

//修改用户信息
const updateUserInfo = () => {
    loading.value = true
    console.log('修改用户信息', userInfo.value)
    http?.request({
        url: "api/User/updateUserInfoByOpenId",
        method: 'POST',
        data: {
            id: userInfo.value!.id,
            name: userInfo.value!.userName,
            address: userInfo.value!.userAddress,
            phone: userInfo.value!.userPhone,
            headshot: userInfo.value!.userImg,
            openId: uni.getStorageSync('openid')
        }
    }).then((res: any) => {
        if (res.code == 200) {
            uni.showToast({
                title: '修改成功!',
                icon: 'success'
            })
            getUserInfoByToken(uni.getStorageSync('openid'))
        } else {
            uni.showToast({
                title: '修改失败!',
                icon: 'error'
            })
        }
    }).catch((err: any) => {
        console.log(err)
        uni.showToast({
            title: '网络错误!',
            icon: 'error'
        })
    }).finally(() => {
        loading.value = false
    })
    editState.value = false
}

//修改用户头像
const editUserImg = () => {
    console.log('修改用户头像')
    //@ts-ignore
    wx.chooseMedia({
        count: 1,
        mediaTypes: ['image'],
        sourceType: ['album', 'camera'],
        sizeType: 'compressed',
        camera: 'front',
        success: (res: any) => {
            loading.value = true
            const { tempFiles } = res
            const tempUserImg = tempFiles[0]
            cutImgToSquare(tempUserImg.tempFilePath)
        },
        fail: (err: any) => {
            console.log("调用失败", err)
        },
        complete: (res: any) => {
            console.log("调用完成", res)
        }
    })
}

//将用户图片自动剪切成正方形
const cutImgToSquare = (imgPath: string) => {
    //@ts-ignore
    wx.createSelectorQuery()
        .select('#canvas')
        .fields({ node: true, size: true })
        .exec((res: any) => {
            const canvas = res[0].node
            const ctx = canvas.getContext('2d')
            const image = canvas.createImage()
            image.onload = () => {
                const size = Math.min(image.width, image.height)
                canvas.width = size
                canvas.height = size
                ctx.clearRect(0, 0, canvas.width, canvas.height)
                ctx.drawImage(image, (image.width - size) / 2, (image.height - size) / 2, size, size, 0, 0, size, size)
                //@ts-ignore
                wx.canvasToTempFilePath({
                    canvas,
                    success: (res: any) => {
                        console.log("调用成功", res)
                        //上传文件到服务器
                        uploadUserImg(res)
                    },
                    fail: (err: any) => {
                        console.log("调用失败", err)
                        loading.value = false
                        uni.showToast({
                            title: '图片上传失败!',
                            icon: 'error'
                        })
                    },
                    complete: (res: any) => {
                        console.log("调用完成", res)
                    }
                })
            }
            image.src = imgPath
        })
}

//将文件上传到服务器
const uploadUserImg = (file: any) => {
    //@ts-ignore
    wx.uploadFile({
        url: uploadImg,
        filePath: file.tempFilePath,
        name: 'file',
        success: (res: any) => {
            const data = JSON.parse(res.data)
            if (data.code == 200) {
                console.log("图片路径", data.data.filePath)
                userInfo.value!.userImg = data.data.filePath
                editState.value = true
            } else {
                uni.showToast({
                    title: '上传失败!',
                    icon: 'error'
                })
            }
            loading.value = false
        },
        fail: (err: any) => {
            console.log("上传失败", err)
            loading.value = false
            uni.showToast({
                title: '上传失败!',
                icon: 'error'
            })
        },
        complete: (res: any) => {
            console.log("上传完成", res)
        }
    })
}
</script>

<style scoped>
.header {
    height: 25vh;
    width: 100vw;
    position: relative;
    display: flex;
    justify-content: center;
    align-items: center;
}

.bodyer {
    height: fit-content;
    width: 100vw;
}

.user-img {
    position: relative;
    top: 3vh;
}

.footer {
    width: 100vw;
    font-size: 13px;
    text-align: center;
    display: flex;
    justify-content: space-around;
    padding: 2vh 0px;
    color: gray;
}

.footer>view {
    padding: 5px 10px;
}

.goback {
    position: absolute;
    top: 5vh;
    left: 5vw;
}

.user-info {
    width: 90vw;
    margin: auto;
    height: fit-content;
    padding: 10px;
    background-color: #ffffff;
    border-radius: 30rpx;
}

.user-title {
    display: flex;
    align-items: center;
    border-bottom: 2px solid #f4f7fc;
}

.base-info-item {
    background-color: #f6f9ff;
    border-radius: 2px;
    padding: 5px 10px;
    margin-top: 5px;
    font-size: 14px;
}

.user-info-item {
    margin: 10px 0px;
}

.goingauthenticated {
    background-color: #ffffff;
    color: #F56C6C;
    padding: 5px 10px;
    border-radius: 10px 10px 0px 0px;
    display: flex;
    align-items: center;
    width: fit-content;
    margin-left: auto;
}
</style>


http://www.niftyadmin.cn/n/5861858.html

相关文章

Django Admin: 实现基于数据库实际值的动态过滤器

在 Django Admin 中,我们经常需要使用 list_filter 来为管理界面添加过滤功能。然而,有时我们希望过滤器能够动态地反映数据库中的实际值,而不是依赖于预定义的选项。本文将介绍如何实现一个基于数据库实际值的动态过滤器,以 ECR 仓库的区域过滤为例。 问题背景 在管理 E…

《代码随想录第三十九天》——背包问题二维、背包问题一维、分割等和子集

《代码随想录第三十九天》——背包问题二维、背包问题一维、分割等和子集 本篇文章的所有内容仅基于C撰写。 1. 背包问题二维 背包问题掌握01背包和完全背包即可&#xff0c;多重背包都比较少。 而完全背包又是也是01背包稍作变化而来&#xff0c;即&#xff1a;完全背包的物…

面对低消费欲人群,我们如何开发其需求?

在市场增量放缓的当下&#xff0c;开发深度开发各层次的人群已经成为现实需求。低消费欲人群并非“没有需求”&#xff0c;而是更谨慎、更理性。他们可能对价格敏感&#xff0c;但对实用性、情感共鸣和生活品质的追求依然存在。就让我们从以下四个角度&#xff0c;拆解如何激发…

Web - JS基础语法与表达式

概述 这篇文章主要介绍了 JavaScript 的基础语法&#xff0c;包括代码书写位置、ERPL 环境、变量&#xff08;命名规则、默认值、初始化&#xff09;、数据类型&#xff08;基本和复杂&#xff0c;及各类型特点、转换&#xff09;、表达式和运算符&#xff08;算数、特殊算数、…

Repeated Sequence

记suma[1]a[2]a[3]...a[n]。 该序列以a[1]&#xff0c;a[2]&#xff0c;a[3]....a[n]为循环节&#xff0c;明显的&#xff0c;问题可转化为:s%sum是否为该序列的某个连续子序列和。 断环为链。将a复制一份。 枚举a[i]为左端点的所有区间的和。再查找s是否存在。二分O&#x…

langchain 调用 本地部署 deepseek-r1 模型

如何本地部署 deepseek 请参考&#xff08;windows 部署安装 大模型 DeepSeek-R1&#xff09; LangChain 就是一个 LLM 编程框架&#xff0c;你想开发一个基于 LLM 应用&#xff0c;需要什么组件它都有&#xff0c;直接使用就行&#xff1b; 下面是langchain 调用 本地部署 de…

洛谷B3619(B3620)

B3619 10 进制转 x 进制 - 洛谷 B3620 x 进制转 10 进制 - 洛谷 代码区&#xff1a; #include<algorithm> #include<iostream> #include<vector> using namespace std;int main(){int n,x;cin >> n >> x;vector<char> arry;while(n){if(…

电子行业新“芯”突破:ZCC5143 同步降压控制器替代LM5143

在科技发展日新月异的当下&#xff0c;电子设备性能的提升不仅依赖于核心处理器&#xff0c;电源管理芯片的优劣同样起着举足轻重的作用。从日常使用的智能手机、平板电脑&#xff0c;到汽车电子、工业控制等专业领域&#xff0c;电源管理芯片如同设备的“能量心脏”&#xff0…