yunzer_go/mobile/pages/profile/editprofile.vue
2025-10-27 23:13:08 +08:00

1036 lines
26 KiB
Vue

<template>
<view class="editprofile-container">
<!-- 移动设备顶部状态栏 -->
<view v-if="isMobile" class="top_bar">
<view class="chat-header">
<view class="header-left">
<view class="header-icon" @click="goBack">
<i class="fas fa-arrow-left"></i>
</view>
</view>
<view class="header-title">编辑个人资料</view>
<view class="header-right">
<view class="header-icon" @click="saveProfile">
<i class="fas fa-check"></i>
</view>
</view>
</view>
</view>
<!-- 浏览器环境头部 -->
<view v-else class="chat-header">
<view class="header-left">
<view class="header-icon" @click="goBack">
<i class="fas fa-arrow-left"></i>
</view>
</view>
<view class="header-title">编辑个人资料</view>
<view class="header-right">
<view class="header-icon" @click="saveProfile">
<i class="fas fa-check"></i>
</view>
</view>
</view>
<!-- 主要内容区域 -->
<view class="editprofile-content">
<view class="profile-form">
<!-- 头像区域 -->
<!-- <view class="avatar-section">
<image
:src="profile.avatar || defaultAvatar"
class="profile-avatar"
mode="aspectFill"
@error="handleAvatarError"
/>
<view class="avatar-upload-btn" @click="changeAvatar">
<i class="fas fa-camera"></i>
<text>更换头像</text>
</view>
</view> -->
<!-- 表单区域 -->
<view class="form-section">
<!-- 姓名 -->
<view class="form-group">
<view class="form-label">
<i class="fas fa-user"></i>
<text>姓名</text>
</view>
<input
type="text"
v-model="profile.name"
placeholder="请输入真实姓名"
maxlength="20"
class="form-input"
/>
</view>
<!-- 生日 -->
<view class="form-group">
<view class="form-label">
<i class="fas fa-birthday-cake"></i>
<text>生日</text>
</view>
<picker
mode="date"
:value="profile.birthday"
@change="onBirthdayChange"
class="form-picker"
>
<view class="picker-display">
{{ profile.birthday || "请选择生日" }}
<i class="fas fa-calendar-alt"></i>
</view>
</picker>
</view>
<!-- 性别 -->
<view class="form-group">
<view class="form-label">
<i class="fas fa-venus-mars"></i>
<text>性别</text>
</view>
<view class="gender-options">
<view
class="gender-option"
:class="{ active: profile.gender === '男' }"
@click="profile.gender = '男'"
>
<i class="fas fa-male"></i>
<text>男</text>
</view>
<view
class="gender-option"
:class="{ active: profile.gender === '女' }"
@click="profile.gender = '女'"
>
<i class="fas fa-female"></i>
<text>女</text>
</view>
<view
class="gender-option"
:class="{ active: profile.gender === '保密' }"
@click="profile.gender = '保密'"
>
<i class="fas fa-lock"></i>
<text>保密</text>
</view>
</view>
</view>
<!-- 婚姻状况 -->
<view class="form-group">
<view class="form-label">
<i class="fas fa-heart"></i>
<text>婚姻状况</text>
</view>
<view class="marriage-options">
<view
class="marriage-option"
:class="{ active: profile.marriage === '未婚' }"
@click="profile.marriage = '未婚'"
>
<i class="fas fa-user"></i>
<text>未婚</text>
</view>
<view
class="marriage-option"
:class="{ active: profile.marriage === '已婚' }"
@click="profile.marriage = '已婚'"
>
<i class="fas fa-heart"></i>
<text>已婚</text>
</view>
<view
class="marriage-option"
:class="{ active: profile.marriage === '离异' }"
@click="profile.marriage = '离异'"
>
<i class="fas fa-heart-broken"></i>
<text>离异</text>
</view>
<view
class="marriage-option"
:class="{ active: profile.marriage === '保密' }"
@click="profile.marriage = '保密'"
>
<i class="fas fa-lock"></i>
<text>保密</text>
</view>
</view>
</view>
<!-- 家庭住址 -->
<view class="form-group">
<view class="form-label">
<i class="fas fa-home"></i>
<text>家庭住址</text>
</view>
<input
type="text"
v-model="profile.address"
placeholder="请输入家庭住址"
maxlength="100"
class="form-input"
/>
</view>
<!-- 手机号 -->
<view class="form-group">
<view class="form-label">
<i class="fas fa-phone"></i>
<text>手机号</text>
</view>
<input
type="text"
v-model="profile.phone"
placeholder="请输入手机号"
maxlength="11"
class="form-input"
/>
</view>
<!-- 微信号 -->
<view class="form-group">
<view class="form-label">
<i class="fab fa-weixin"></i>
<text>微信号</text>
</view>
<input
type="text"
v-model="profile.wechat"
placeholder="请输入微信号"
maxlength="30"
class="form-input"
/>
</view>
<!-- 电子邮箱 -->
<view class="form-group">
<view class="form-label">
<i class="fas fa-envelope"></i>
<text>电子邮箱</text>
</view>
<input
type="text"
v-model="profile.email"
placeholder="请输入电子邮箱"
maxlength="50"
class="form-input"
/>
</view>
<!-- 个人简介 -->
<view class="form-group">
<view class="form-label">
<i class="fas fa-quote-left"></i>
<text>个人简介</text>
</view>
<textarea
v-model="profile.bio"
placeholder="请简单介绍一下自己"
maxlength="200"
class="form-textarea"
/>
</view>
<!-- 工作经历 -->
<view class="form-group">
<view class="form-label">
<i class="fas fa-briefcase"></i>
<text>工作经历</text>
</view>
<view class="experience-item" v-for="(item, index) in profile.workExperience" :key="index">
<view class="experience-header">
<text class="experience-title">工作经历 {{ index + 1 }}</text>
<view class="experience-actions">
<i class="fas fa-edit" @click="editWorkExperience(index)"></i>
<i class="fas fa-trash" @click="removeWorkExperience(index)" v-if="profile.workExperience.length > 1"></i>
</view>
</view>
<view class="experience-content">
<view class="time-range">
<picker mode="date" :value="item.startDate" @change="(e) => updateWorkExperience(index, 'startDate', e.detail.value)">
<view class="date-picker">
<text>{{ item.startDate || '开始年月' }}</text>
<i class="fas fa-calendar"></i>
</view>
</picker>
<text class="date-separator">至</text>
<picker mode="date" :value="item.endDate" @change="(e) => updateWorkExperience(index, 'endDate', e.detail.value)">
<view class="date-picker">
<text>{{ item.endDate || '结束年月' }}</text>
<i class="fas fa-calendar"></i>
</view>
</picker>
</view>
<input
type="text"
v-model="item.company"
placeholder="公司名称"
maxlength="50"
class="form-input"
/>
<input
type="text"
v-model="item.position"
placeholder="职位"
maxlength="30"
class="form-input"
/>
<textarea
v-model="item.description"
placeholder="工作内容描述"
maxlength="200"
class="form-textarea"
/>
</view>
</view>
<view class="add-experience-btn" @click="addWorkExperience">
<i class="fas fa-plus"></i>
<text>添加工作经历</text>
</view>
</view>
<!-- 教育经历 -->
<view class="form-group">
<view class="form-label">
<i class="fas fa-graduation-cap"></i>
<text>教育经历</text>
</view>
<view class="experience-item" v-for="(item, index) in profile.educationExperience" :key="index">
<view class="experience-header">
<text class="experience-title">教育经历 {{ index + 1 }}</text>
<view class="experience-actions">
<i class="fas fa-edit" @click="editEducationExperience(index)"></i>
<i class="fas fa-trash" @click="removeEducationExperience(index)" v-if="profile.educationExperience.length > 1"></i>
</view>
</view>
<view class="experience-content">
<view class="time-range">
<picker mode="date" :value="item.startDate" @change="(e) => updateEducationExperience(index, 'startDate', e.detail.value)">
<view class="date-picker">
<text>{{ item.startDate || '开始年月' }}</text>
<i class="fas fa-calendar"></i>
</view>
</picker>
<text class="date-separator"></text>
<picker mode="date" :value="item.endDate" @change="(e) => updateEducationExperience(index, 'endDate', e.detail.value)">
<view class="date-picker">
<text>{{ item.endDate || '结束年月' }}</text>
<i class="fas fa-calendar"></i>
</view>
</picker>
</view>
<input
type="text"
v-model="item.school"
placeholder="学校名称"
maxlength="50"
class="form-input"
/>
<input
type="text"
v-model="item.major"
placeholder="专业"
maxlength="30"
class="form-input"
/>
<input
type="text"
v-model="item.degree"
placeholder="学历/学位"
maxlength="20"
class="form-input"
/>
<textarea
v-model="item.description"
placeholder="学习内容描述"
maxlength="200"
class="form-textarea"
/>
</view>
</view>
<view class="add-experience-btn" @click="addEducationExperience">
<i class="fas fa-plus"></i>
<text>添加教育经历</text>
</view>
</view>
</view>
<!-- 保存按钮 -->
<view class="submit-section">
<view class="submit-btn" @click="saveProfile">
<i class="fas fa-save"></i>
<text>保存修改</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
defaultAvatar: "/static/imgs/default_avatar.png",
profile: {
avatar: "",
name: "",
gender: "保密",
birthday: "",
email: "",
marriage: "保密",
address: "",
phone: "",
wechat: "",
bio: "",
workExperience: [
{
startDate: "",
endDate: "",
company: "",
position: "",
description: ""
}
],
educationExperience: [
{
startDate: "",
endDate: "",
school: "",
major: "",
degree: "",
description: ""
}
],
},
};
},
computed: {
isMobile() {
return getApp().globalData.isMobile;
},
},
methods: {
goBack() {
uni.navigateBack();
},
changeAvatar() {
uni.chooseImage({
count: 1,
sizeType: ["compressed"],
sourceType: ["album", "camera"],
success: (res) => {
this.profile.avatar = res.tempFilePaths[0];
uni.showToast({
title: "头像已选择",
icon: "success",
});
},
fail: (err) => {
console.error("选择头像失败:", err);
uni.showToast({
title: "选择头像失败",
icon: "none",
});
},
});
},
handleAvatarError() {
this.profile.avatar = this.defaultAvatar;
},
onBirthdayChange(e) {
this.profile.birthday = e.detail.value;
},
// 工作经历相关方法
addWorkExperience() {
this.profile.workExperience.push({
startDate: "",
endDate: "",
company: "",
position: "",
description: ""
});
},
removeWorkExperience(index) {
if (this.profile.workExperience.length > 1) {
this.profile.workExperience.splice(index, 1);
}
},
updateWorkExperience(index, field, value) {
this.$set(this.profile.workExperience[index], field, value);
},
editWorkExperience(index) {
// 可以添加编辑逻辑,比如展开/收起
console.log('编辑工作经历', index);
},
// 教育经历相关方法
addEducationExperience() {
this.profile.educationExperience.push({
startDate: "",
endDate: "",
school: "",
major: "",
degree: "",
description: ""
});
},
removeEducationExperience(index) {
if (this.profile.educationExperience.length > 1) {
this.profile.educationExperience.splice(index, 1);
}
},
updateEducationExperience(index, field, value) {
this.$set(this.profile.educationExperience[index], field, value);
},
editEducationExperience(index) {
// 可以添加编辑逻辑,比如展开/收起
console.log('编辑教育经历', index);
},
saveProfile() {
// 验证表单
if (!this.profile.name.trim()) {
uni.showToast({
title: "请输入姓名",
icon: "none",
});
return;
}
if (!this.profile.phone.trim()) {
uni.showToast({
title: "请输入手机号",
icon: "none",
});
return;
}
// 验证手机号格式
const phoneRegex = /^1[3-9]\d{9}$/;
if (!phoneRegex.test(this.profile.phone)) {
uni.showToast({
title: "请输入正确的手机号",
icon: "none",
});
return;
}
if (
this.profile.wechat &&
!/^[a-zA-Z0-9_-]{6,20}$/.test(this.profile.wechat)
) {
uni.showToast({
title: "微信号格式不正确",
icon: "none",
});
return;
}
if (
this.profile.email &&
!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(this.profile.email)
) {
uni.showToast({
title: "邮箱格式不正确",
icon: "none",
});
return;
}
// 保存逻辑
uni.showLoading({
title: "保存中...",
});
// 模拟保存
setTimeout(() => {
uni.hideLoading();
uni.showToast({
title: "保存成功",
icon: "success",
});
// 保存成功后返回上一页
setTimeout(() => {
uni.navigateBack();
}, 1500);
}, 1000);
},
},
};
</script>
<style lang="scss" scoped>
/* 移动设备顶部状态栏 */
.top_bar {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 99999;
height: calc(var(--status-bar-height, 20px) + 88rpx);
background: var(--gradient-primary);
box-shadow: var(--shadow-lg);
}
.top_bar .chat-header {
background: transparent;
border-bottom: none;
box-shadow: none;
width: 100%;
height: 88rpx;
padding: 0 20rpx;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: space-between;
}
/* 浏览器环境头部 */
.chat-header:not(.top_bar .chat-header) {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 9999;
background: var(--gradient-primary);
box-shadow: var(--shadow-lg);
height: calc(var(--status-bar-height) + 88rpx);
padding-top: var(--status-bar-height);
display: flex;
align-items: center;
justify-content: space-between;
padding-left: 20rpx;
padding-right: 20rpx;
box-sizing: border-box;
}
.header-left,
.header-right {
display: flex;
align-items: center;
min-width: 80rpx;
}
.header-right {
justify-content: flex-end;
}
.header-title {
flex: 1;
text-align: center;
color: var(--white);
font-size: 32rpx;
font-weight: 600;
margin: 0 20rpx;
}
.header-icon {
color: var(--white);
font-size: 36rpx;
padding: 10rpx;
border-radius: 50%;
transition: all 0.3s ease;
}
.header-icon:active {
background: rgba(255, 255, 255, 0.2);
transform: scale(0.95);
}
/* 内容区域 */
.editprofile-content {
padding: 30rpx;
padding-top: calc(var(--status-bar-height, 20px) + 118rpx);
min-height: 100vh;
background: var(--background);
box-sizing: border-box;
}
/* 支持安全区域的设备 */
@supports (padding: max(0px)) {
.top_bar {
height: calc(
var(--status-bar-height, 20px) + 88rpx + env(safe-area-inset-top)
);
}
.top_bar .chat-header {
padding-top: env(safe-area-inset-top);
}
.chat-header:not(.top_bar .chat-header) {
height: calc(var(--status-bar-height) + 88rpx + env(safe-area-inset-top));
padding-top: calc(var(--status-bar-height) + env(safe-area-inset-top));
}
.editprofile-content {
padding-top: calc(
var(--status-bar-height, 20px) + 118rpx + env(safe-area-inset-top)
);
}
}
/* 表单容器 */
.profile-form {
background: var(--surface);
border-radius: 16rpx;
box-shadow: var(--shadow-md);
overflow: hidden;
border: 1rpx solid var(--border);
}
/* 头像区域 */
.avatar-section {
display: flex;
flex-direction: column;
align-items: center;
padding: 40rpx 30rpx;
background: var(--gradient-surface);
border-bottom: 1rpx solid var(--border-light);
}
.profile-avatar {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
box-shadow: var(--shadow-lg);
border: 3rpx solid var(--primary-color);
}
.avatar-upload-btn {
display: flex;
align-items: center;
gap: 8rpx;
margin-top: 20rpx;
background: var(--button-secondary);
color: var(--text-color);
padding: 12rpx 24rpx;
border-radius: 50rpx;
font-size: 24rpx;
transition: all 0.3s ease;
border: 1rpx solid var(--border);
}
.avatar-upload-btn:active {
background: var(--button-secondary-hover);
transform: scale(0.98);
}
.avatar-upload-btn i {
font-size: 20rpx;
}
/* 表单区域 */
.form-section {
padding: 30rpx;
}
.form-group {
margin-bottom: 32rpx;
}
.form-label {
display: flex;
align-items: center;
gap: 12rpx;
margin-bottom: 16rpx;
color: var(--text-secondary);
font-size: 28rpx;
font-weight: 500;
}
.form-label i {
color: var(--primary-color);
font-size: 24rpx;
width: 24rpx;
}
.form-input,
.form-textarea {
width: 100%;
padding: 30rpx;
border: 1rpx solid var(--border);
border-radius: 12rpx;
font-size: 28rpx;
background: var(--background-light);
color: var(--text-color);
box-sizing: border-box;
transition: all 0.3s ease;
}
.form-input:focus,
.form-textarea:focus {
border-color: var(--primary-color);
box-shadow: 0 0 0 2rpx rgba(43, 124, 233, 0.1);
outline: none;
}
.form-textarea {
min-height: 80rpx;
resize: none;
}
/* 性别选择 */
.gender-options {
display: flex;
gap: 16rpx;
margin-top: 8rpx;
}
/* 婚姻状况选择 */
.marriage-options {
display: flex;
flex-wrap: wrap;
gap: 12rpx;
margin-top: 8rpx;
}
.gender-option {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 8rpx;
padding: 20rpx 16rpx;
background: var(--gray-lighter);
border: 1rpx solid var(--border-light);
border-radius: 12rpx;
transition: all 0.3s ease;
cursor: pointer;
}
.gender-option.active {
background: var(--primary-color);
border-color: var(--primary-color);
color: var(--white);
box-shadow: var(--shadow-md);
transform: translateY(-2rpx);
}
.gender-option:not(.active):active {
background: var(--primary-light);
color: var(--white);
transform: scale(0.98);
}
.gender-option i {
font-size: 32rpx;
}
.gender-option text {
font-size: 24rpx;
font-weight: 500;
}
.marriage-option {
flex: 1;
min-width: calc(50% - 6rpx);
display: flex;
flex-direction: column;
align-items: center;
gap: 8rpx;
padding: 20rpx 16rpx;
background: var(--gray-lighter);
border: 1rpx solid var(--border-light);
border-radius: 12rpx;
transition: all 0.3s ease;
cursor: pointer;
}
.marriage-option.active {
background: var(--primary-color);
border-color: var(--primary-color);
color: var(--white);
box-shadow: var(--shadow-md);
transform: translateY(-2rpx);
}
.marriage-option:not(.active):active {
background: var(--primary-light);
color: var(--white);
transform: scale(0.98);
}
.marriage-option i {
font-size: 28rpx;
}
.marriage-option text {
font-size: 22rpx;
font-weight: 500;
}
/* 经历相关样式 */
.experience-item {
background: var(--white);
border: 1rpx solid var(--border-light);
border-radius: 12rpx;
margin-bottom: 16rpx;
overflow: hidden;
}
.experience-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 24rpx;
background: var(--gray-lighter);
border-bottom: 1rpx solid var(--border-light);
}
.experience-title {
font-size: 28rpx;
font-weight: 600;
color: var(--text-primary);
}
.experience-actions {
display: flex;
gap: 16rpx;
}
.experience-actions i {
font-size: 24rpx;
color: var(--text-secondary);
padding: 8rpx;
border-radius: 6rpx;
transition: all 0.3s ease;
}
.experience-actions i:active {
background: var(--primary-light);
color: var(--white);
}
.experience-content {
padding: 24rpx;
}
.time-range {
display: flex;
align-items: center;
gap: 16rpx;
margin-bottom: 20rpx;
}
.date-picker {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
padding: 16rpx 20rpx;
background: var(--gray-lighter);
border: 1rpx solid var(--border-light);
border-radius: 8rpx;
font-size: 26rpx;
color: var(--text-primary);
}
.date-picker text {
color: var(--text-secondary);
}
.date-picker i {
font-size: 20rpx;
color: var(--text-secondary);
}
.date-separator {
font-size: 24rpx;
color: var(--text-secondary);
font-weight: 500;
}
.add-experience-btn {
display: flex;
align-items: center;
justify-content: center;
gap: 12rpx;
padding: 20rpx;
background: var(--gray-lighter);
border: 2rpx dashed var(--border-light);
border-radius: 12rpx;
color: var(--text-secondary);
font-size: 26rpx;
transition: all 0.3s ease;
cursor: pointer;
}
.add-experience-btn:active {
background: var(--primary-light);
color: var(--white);
border-color: var(--primary-color);
}
.add-experience-btn i {
font-size: 24rpx;
}
/* 日期选择器 */
.form-picker {
width: 100%;
}
.picker-display {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx 16rpx;
background: var(--background-light);
border: 1rpx solid var(--border);
border-radius: 12rpx;
font-size: 28rpx;
color: var(--text-color);
transition: all 0.3s ease;
}
.picker-display:active {
border-color: var(--primary-color);
background: var(--primary-light);
color: var(--white);
}
.picker-display i {
color: var(--text-muted);
font-size: 24rpx;
}
/* 保存按钮区域 */
.submit-section {
padding: 30rpx;
background: var(--gray-lighter);
border-top: 1rpx solid var(--border-light);
}
.submit-btn {
display: flex;
align-items: center;
justify-content: center;
gap: 12rpx;
width: 100%;
padding: 24rpx 0;
background: var(--gradient-primary);
color: var(--white);
border-radius: 12rpx;
font-size: 32rpx;
font-weight: 600;
box-shadow: var(--shadow-md);
transition: all 0.3s ease;
border: none;
}
.submit-btn:active {
opacity: 0.9;
transform: translateY(1rpx);
box-shadow: var(--shadow);
}
.submit-btn i {
font-size: 28rpx;
}
</style>