|
|
- <template>
- <view class="profile-container">
- <!-- 个人信息表单 -->
- <view class="form-container">
- <view class="form-title">个人信息</view>
-
- <!-- 昵称 -->
- <view class="form-item">
- <view class="label">
- <text class="required">*</text>
- <text>昵称</text>
- </view>
- <uv-input
- v-model="userInfo.name"
- placeholder="请输入昵称"
- type="nickname"
- :customStyle="inputStyle"
- border="bottom"
- ></uv-input>
- </view>
-
- <!-- 电话 -->
- <view class="form-item">
- <view class="label">
- <text class="required">*</text>
- <text>电话</text>
- </view>
- <uv-input
- v-model="userInfo.phone"
- placeholder="请输入手机号"
- :customStyle="inputStyle"
- border="bottom"
- type="number"
- ></uv-input>
- </view>
-
- <!-- 头像 -->
- <view class="form-item">
- <view class="label">
- <text class="required">*</text>
- <text>头像</text>
- </view>
- <!-- #ifdef MP-WEIXIN -->
- <button class="avatar-container" open-type="chooseAvatar" @chooseavatar="onChooseAvatar">
- <view
- v-if="userInfo.avatar === 'undefined'"
- class="avatar-image"
- >
- <uv-icon name="camera" size="40" color="white"></uv-icon>
- </view>
- <image
- v-else
- :src="userInfo.avatar || '/static/default-avatar.png'"
- class="avatar-image"
- mode="aspectFill"
- ></image>
-
- </button>
- <!-- #endif -->
-
- <!-- #ifndef MP-WEIXIN -->
- <button class="avatar-container" @click="chooseImageH5">
- <view
- v-if="userInfo.avatar === 'undefined'"
- class="avatar-image"
- >
- <uv-icon name="camera" size="40" color="white"></uv-icon>
- </view>
- <image
- v-else
- :src="userInfo.avatar || '/static/default-avatar.png'"
- class="avatar-image"
- mode="aspectFill"
- ></image>
-
- </button>
- <!-- #endif -->
- </view>
- </view>
-
- <!-- 固定底部保存按钮 -->
- <view class="save-button-container">
- <uv-button
- @click="saveProfile"
- :customStyle="saveButtonStyle"
- shape="circle"
- >
- 保存
- </uv-button>
- </view>
- </view>
- </template>
-
- <script>
- export default {
- data() {
- return {
- userInfo: {
- avatar: 'undefined',
- name: '',
- phone: ''
- },
- saveButtonStyle: {
- backgroundColor: '#06DADC',
- borderRadius: '41rpx',
- height: '94rpx',
- width: '594rpx',
- border: 'none',
- color: '#fff',
- fontSize: '32rpx',
- fontWeight: '500'
- },
- inputStyle: {
- backgroundColor: '#fff',
- borderRadius: '12rpx',
- padding: '0 -20rpx',
- fontSize: '28rpx'
- }
- }
- },
- methods: {
-
-
-
- // 选择头像并上传到OSS
- async onChooseAvatar(e) {
- console.log('选择头像回调', e);
- if (e.detail.avatarUrl) {
- try {
- // 显示上传中提示
- uni.showLoading({ title: '上传头像中...' });
-
- // 构造文件对象
- const file = {
- path: e.detail.avatarUrl,
- tempFilePath: e.detail.avatarUrl
- };
-
- // 上传到OSS
- const uploadResult = await this.$utils.uploadImage(file);
-
- uni.hideLoading();
-
- if (uploadResult.success) {
- // 上传成功,更新头像URL
- this.userInfo.avatar = uploadResult.url;
- console.log('头像上传成功', uploadResult.url);
- uni.showToast({
- title: '头像上传成功',
- icon: 'success'
- });
- } else {
-
- }
- } catch (error) {
- uni.hideLoading();
- console.error('头像上传异常:', error);
- // 异常情况下使用本地头像
- // this.userInfo.avatar = e.detail.avatarUrl;
- uni.showToast({
- title: '头像处理异常,使用本地头像',
- icon: 'none'
- });
- }
- } else {
- uni.showToast({
- title: '头像选择失败',
- icon: 'none'
- });
- }
- },
-
- // 公众号/H5 选择图片并上传头像
- // #ifndef MP-WEIXIN
- async chooseImageH5() {
- try {
- const res = await uni.chooseImage({
- count: 1,
- sizeType: ['compressed'],
- sourceType: ['album', 'camera']
- })
-
- const filePath = (res.tempFilePaths && res.tempFilePaths[0])
- || (res.tempFiles && res.tempFiles[0] && (res.tempFiles[0].path || res.tempFiles[0].tempFilePath))
-
- if (!filePath) {
- uni.showToast({ title: '未选择图片', icon: 'none' })
- return
- }
-
- uni.showLoading({ title: '上传头像中...' })
-
- const file = { path: filePath, tempFilePath: filePath }
- const uploadResult = await this.$utils.uploadImage(file)
-
- uni.hideLoading()
-
- if (uploadResult && uploadResult.success) {
- this.userInfo.avatar = uploadResult.url
- uni.showToast({ title: '头像上传成功', icon: 'success' })
- } else {
- // 上传失败则先本地显示
- this.userInfo.avatar = filePath
- uni.showToast({ title: '头像已选择', icon: 'none' })
- }
- } catch (error) {
- uni.hideLoading()
- console.error('选择/上传头像异常:', error)
- uni.showToast({ title: '头像处理异常', icon: 'none' })
- }
- },
- // #endif
-
- // 保存资料
- async saveProfile() {
- if (!this.userInfo.name?.trim()) {
- uni.showToast({
- title: '请输入昵称',
- icon: 'none'
- })
- return
- }
-
- if (!this.userInfo.phone?.trim()) {
- uni.showToast({
- title: '请输入手机号',
- icon: 'none'
- })
- return
- }
-
- // 简单的手机号验证
- const phoneReg = /^1[3-9]\d{9}$/
- if (!phoneReg.test(this.userInfo.phone)) {
- uni.showToast({
- title: '请输入正确的手机号',
- icon: 'none'
- })
- return
- }
-
- // TODO: 调用API保存用户信息
- const res = await this.$api.login.updateUserInfo({
- avatar: this.userInfo.avatar,
- name: this.userInfo.name,
- phone: this.userInfo.phone
- })
- if (res.code === 200) {
- uni.showToast({
- title: '保存成功',
- icon: 'success'
- })
-
- // 延迟返回上一页
- setTimeout(() => {
- uni.navigateBack()
- }, 1500)
- }
- },
-
- // 获取个人信息
- async getProfile() {
- const res = await this.$api.login.getUserInfo()
- if (res.code === 200) {
- this.userInfo = res.result
- this.$store.dispatch('updateUserInfo', this.userInfo)
- }
- }
- },
- onLoad() {
- this.getProfile()
- // 3秒后隐藏遮罩层
-
- }
- }
- </script>
-
- <style lang="scss" scoped>
- .profile-container {
- min-height: 100vh;
- background-color: #f5f5f5;
- padding: 40rpx 32rpx 200rpx;
-
- .form-container {
- background: #fff;
- border-radius: 20rpx;
- padding: 40rpx 32rpx;
-
- .form-title {
- font-size: 36rpx;
- font-weight: 600;
- color: #333;
- margin-bottom: 60rpx;
- }
-
- .form-item {
- margin-bottom: 60rpx;
-
- &:last-child {
- margin-bottom: 0;
- }
-
- .label {
- display: flex;
- align-items: center;
- margin-bottom: 20rpx;
- font-size: 28rpx;
- color: #333;
-
- .required {
- color: #ff4757;
- margin-right: 8rpx;
- }
- }
- }
-
- .avatar-container {
- position: relative;
- width: 200rpx;
- height: 200rpx;
- border-radius: 16rpx;
- overflow: hidden;
- display: block;
- text-align: left;
- margin: 0;
- padding: 0;
- background: none;
- border: none;
-
- .avatar-image {
- width: 100%;
- height: 100%;
- background: #00000080;
- display: flex;
- align-items: center;
- justify-content: center;
- }
-
- .avatar-mask {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background: rgba(0, 0, 0, 0.6);
- display: flex;
- align-items: center;
- justify-content: center;
- color: #fff;
- font-size: 24rpx;
- transition: opacity 1s ease-out;
-
- &.fade-out {
- opacity: 0;
- }
- }
- }
- }
-
- .save-button-container {
- position: fixed;
- bottom: 60rpx;
- left: 50%;
- transform: translateX(-50%);
- z-index: 999;
- }
- }
- </style>
|