343 lines
8.0 KiB
Vue
343 lines
8.0 KiB
Vue
<template>
|
||
<view class="mine-user-edit">
|
||
<view class="edit-content">
|
||
<view class="flex-row-between edit-cell">
|
||
<text class="title">头像</text>
|
||
<button class="flex-row-end user-avator" @click="chooseavatar">
|
||
<image class="avator-icon" :src="userInfo.head_pic_url" />
|
||
<!-- <image class="arrow-icon" :src="`${imgPrefix}right-arrow.png`" /> -->
|
||
</button>
|
||
</view>
|
||
<view class="flex-row-between edit-cell">
|
||
<text class="title">昵称</text>
|
||
<input class="fs-24 app-fc-main SourceHanSansCN-Medium edit-input" type="nickname"
|
||
placeholder-class="fs-24 app-fc-normal SourceHanSansCN-Regular app-text-right"
|
||
:value="userInfo.nick_name" placeholder="点击输入昵称" @change="
|
||
(e) =>
|
||
onChange(e.detail.value && e.detail.value.trim(), 'nick_name')
|
||
|
||
" />
|
||
</view>
|
||
<form-cell title="出生年月" type="checkDate" placeholderText="选择出生日期" :value="userInfo.birthday"
|
||
:defaultDate="userInfo.birthday" @onChange="(value) => onChange(value, 'birthday')" />
|
||
<form-cell title="性别" type="custom" :showRightArrow="false" :noBorder="true">
|
||
<view class="flex-row-end edit-sex" slot="right">
|
||
<view class="flex-center fs-24 app-fc-main SourceHanSansCN-Medium sex-item"
|
||
:class="[userInfo.sex === 1 ? 'active man' : '']" @click="onChange(1, 'sex')">
|
||
|
||
<image class="sex-item-img"
|
||
:src="userInfo.sex === 1 ? `${imgPrefix}whiteMale.png` : `${imgPrefix}record-maleImg.png`">
|
||
</image>
|
||
|
||
</view>
|
||
<view class="flex-center fs-24 app-fc-main SourceHanSansCN-Medium sex-item"
|
||
:class="[userInfo.sex === 2 ? 'active women' : '']" @click="onChange(2, 'sex')">
|
||
<image class="sex-item-img"
|
||
:src="userInfo.sex === 2 ? `${imgPrefix}whiteFemale.png` : `${imgPrefix}record-femaleImg.png`">
|
||
</image>
|
||
</view>
|
||
</view>
|
||
</form-cell>
|
||
</view>
|
||
|
||
<view class="footer">
|
||
<view class="footerBtn" @click="onsubmit()">
|
||
保存
|
||
</view>
|
||
<view class="bottom-safe-area"></view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import FormCell from "../../../components/FormCell.vue";
|
||
import {
|
||
updateUserInfo,
|
||
getUserInfo
|
||
} from "../../../api/user";
|
||
import appConfig from "../../../constants/app.config";
|
||
|
||
import {
|
||
imgPrefix
|
||
} from "@/utils/common";
|
||
import {
|
||
uploadImageToOSS_PUT
|
||
} from "@/utils/oss";
|
||
|
||
export default {
|
||
components: {
|
||
FormCell,
|
||
},
|
||
data() {
|
||
return {
|
||
userInfo: {
|
||
head_pic_url: "",
|
||
head_pic: "",
|
||
nick_name: "",
|
||
birthday: "",
|
||
sex: 0,
|
||
},
|
||
appConfig,
|
||
imgPrefix
|
||
};
|
||
},
|
||
onShow() {
|
||
// 直接从 store(缓存)中获取用户信息并映射到表单字段
|
||
const storeUserInfo = this.$store.state?.user?.userInfo || {};
|
||
if (storeUserInfo && Object.keys(storeUserInfo).length > 0) {
|
||
// 将 gender 转换为 sex: "male" -> 1, "female" -> 2, 其他 -> 0
|
||
let sex = 0;
|
||
if (storeUserInfo.gender === 'male') {
|
||
sex = 1;
|
||
} else if (storeUserInfo.gender === 'female') {
|
||
sex = 2;
|
||
} else if (storeUserInfo.sex) {
|
||
// 兼容旧的 sex 字段
|
||
sex = storeUserInfo.sex;
|
||
}
|
||
|
||
// 格式化生日:将 ISO 8601 格式 (2006-01-02T00:00:00+08:00) 转换为 YYYY-MM-DD 格式
|
||
let birthday = storeUserInfo.birthday || '';
|
||
if (birthday) {
|
||
// 如果是 ISO 8601 格式,提取日期部分
|
||
if (birthday.includes('T')) {
|
||
birthday = birthday.split('T')[0];
|
||
}
|
||
// 确保格式为 YYYY-MM-DD
|
||
const dateMatch = birthday.match(/^(\d{4})-(\d{2})-(\d{2})/);
|
||
if (!dateMatch) {
|
||
// 如果不是标准格式,尝试转换
|
||
const date = new Date(birthday);
|
||
if (!isNaN(date.getTime())) {
|
||
const year = date.getFullYear();
|
||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||
const day = String(date.getDate()).padStart(2, '0');
|
||
birthday = `${year}-${month}-${day}`;
|
||
}
|
||
}
|
||
}
|
||
|
||
this.userInfo = {
|
||
head_pic_url: storeUserInfo.avatar || storeUserInfo.head_pic_url || storeUserInfo.head_pic || '',
|
||
head_pic: storeUserInfo.avatar || storeUserInfo.head_pic || storeUserInfo.head_pic_url || '',
|
||
nick_name: storeUserInfo.nickname || storeUserInfo.nick_name || storeUserInfo.username || '',
|
||
birthday: birthday,
|
||
sex: sex,
|
||
};
|
||
}
|
||
},
|
||
methods: {
|
||
// 保存
|
||
onsubmit() {
|
||
const {
|
||
head_pic,
|
||
nick_name,
|
||
birthday,
|
||
sex
|
||
} = this.userInfo;
|
||
if (!head_pic || !nick_name) {
|
||
uni.showToast({
|
||
icon: "none",
|
||
title: "请将昵称和头像填写完整",
|
||
});
|
||
return;
|
||
}
|
||
// 将 sex 转换为 gender: 1 -> "male", 2 -> "female", 其他 -> "other"
|
||
let gender = "other";
|
||
if (sex === 1) {
|
||
gender = "male";
|
||
} else if (sex === 2) {
|
||
gender = "female";
|
||
}
|
||
uni.showLoading({
|
||
title: "处理中..."
|
||
});
|
||
|
||
// 构建请求参数
|
||
const params = {
|
||
username: nick_name,
|
||
gender: gender,
|
||
birthday: birthday,
|
||
};
|
||
|
||
// 如果头像地址不是 https 开头,才传给后端
|
||
if (head_pic && !head_pic.startsWith('https://')) {
|
||
params.avatar = head_pic;
|
||
}
|
||
|
||
updateUserInfo(params).then(() => {
|
||
uni.hideLoading();
|
||
uni.navigateBack();
|
||
}).catch((err) => {
|
||
uni.hideLoading();
|
||
console.error('更新用户信息失败:', err);
|
||
});
|
||
},
|
||
// 更新头像
|
||
chooseavatar() {
|
||
let that = this;
|
||
|
||
uni.showLoading({
|
||
title: "上传中..."
|
||
});
|
||
|
||
uni.chooseImage({
|
||
count: 1, // 只选一张图片
|
||
sourceType: ['album', 'camera'], // 来源:相册、相机
|
||
success: async function(res) {
|
||
try {
|
||
const { url, objectKey } = await uploadImageToOSS_PUT(res.tempFilePaths[0]);
|
||
that.userInfo.head_pic_url = url; // 同时更新 head_pic_url,因为模板使用的是这个字段
|
||
that.userInfo.head_pic = objectKey;
|
||
that.$forceUpdate();
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: "上传成功",
|
||
icon: "success",
|
||
});
|
||
} catch (error) {
|
||
console.error('头像上传失败:', error);
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: error?.message || "头像上传失败",
|
||
icon: "none"
|
||
});
|
||
}
|
||
},
|
||
fail: function(err) {
|
||
console.log('选择图片失败:', err.errMsg);
|
||
uni.hideLoading();
|
||
}
|
||
});
|
||
},
|
||
onChange(value, key) {
|
||
this.userInfo[key] = value;
|
||
this.$forceUpdate();
|
||
},
|
||
},
|
||
};
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
.mine-user-edit {
|
||
background-color: #ffecf3;
|
||
height: 100vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
|
||
.edit-content {
|
||
background-color: #fff;
|
||
border-radius: 16rpx;
|
||
padding: 0rpx 24rpx;
|
||
width: calc(100vw - 40rpx);
|
||
margin: 20rpx auto;
|
||
box-sizing: border-box;
|
||
|
||
|
||
.edit-cell {
|
||
border-bottom: 1rpx solid #ececec;
|
||
height: 110rpx;
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
|
||
.title {
|
||
color: #3D3D3D;
|
||
font-size: 24rpx;
|
||
|
||
.required {
|
||
color: #FF19A0;
|
||
}
|
||
}
|
||
|
||
.avator-icon {
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
border-radius: 80rpx;
|
||
background: gray;
|
||
}
|
||
|
||
.arrow-icon {
|
||
width: 11rpx;
|
||
height: 18rpx;
|
||
}
|
||
|
||
.edit-input {
|
||
height: 100%;
|
||
text-align: right;
|
||
flex: 1;
|
||
margin-left: 30rpx;
|
||
font-size: 24rpx;
|
||
}
|
||
}
|
||
|
||
.edit-sex {
|
||
width: 100%;
|
||
}
|
||
|
||
.sex-item {
|
||
width: 120rpx;
|
||
height: 64rpx;
|
||
background: #f9f7f9;
|
||
border-radius: 16rpx 16rpx 16rpx 16rpx;
|
||
margin-left: 50rpx;
|
||
|
||
&-img {
|
||
width: 28rpx;
|
||
height: 28rpx;
|
||
}
|
||
|
||
&.active {
|
||
color: #fff;
|
||
|
||
&.man {
|
||
background: #FF19A0;
|
||
}
|
||
|
||
&.women {
|
||
background: #FF19A0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.user-avator {
|
||
margin: 0;
|
||
background: #fff;
|
||
border: 0;
|
||
padding: 0;
|
||
border-color: transparent;
|
||
padding-left: 100rpx;
|
||
|
||
&::after {
|
||
border: none;
|
||
}
|
||
}
|
||
|
||
.footer {
|
||
background-color: #fff;
|
||
border-radius: 32rpx 32rpx 0px 0px;
|
||
|
||
.footerBtn {
|
||
color: #fff;
|
||
background-color: #FF19A0;
|
||
width: calc(100% - 48rpx);
|
||
margin: auto;
|
||
margin-bottom: 24rpx;
|
||
margin-top: 12rpx;
|
||
border-radius: 100px;
|
||
text-align: center;
|
||
padding: 32rpx 0rpx;
|
||
}
|
||
|
||
.bottom-safe-area {
|
||
padding-bottom: constant(safe-area-inset-bottom);
|
||
/* 兼容 iOS < 11.2 */
|
||
padding-bottom: env(safe-area-inset-bottom);
|
||
/* 兼容 iOS >= 11.2 */
|
||
}
|
||
}
|
||
|
||
|
||
}
|
||
</style> |