first commit
This commit is contained in:
@@ -0,0 +1,375 @@
|
||||
// pages/edit-profile/index.js
|
||||
const { userApi } = require("../../utils/api");
|
||||
const AuthUtil = require("../../utils/auth");
|
||||
|
||||
Page({
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
username: '',
|
||||
nickname: '',
|
||||
originalUsername: '',
|
||||
originalNickname: '',
|
||||
loading: false,
|
||||
// 密码相关
|
||||
hasPassword: false, // 用户是否已设置密码
|
||||
oldPassword: '',
|
||||
newPassword: '',
|
||||
confirmPassword: '',
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {
|
||||
this.loadUserInfo();
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow() {
|
||||
// 每次显示时刷新用户信息
|
||||
this.loadUserInfo();
|
||||
},
|
||||
|
||||
/**
|
||||
* 加载用户信息
|
||||
*/
|
||||
loadUserInfo() {
|
||||
const userInfo = AuthUtil.getUserInfo();
|
||||
|
||||
// 对于编辑页面,为了确保has_password字段的准确性,总是从服务器获取最新信息
|
||||
// 但先使用本地信息快速显示,避免页面闪烁
|
||||
if (userInfo && userInfo.username) {
|
||||
this.setData({
|
||||
username: userInfo.username || '',
|
||||
nickname: userInfo.nickname || '',
|
||||
originalUsername: userInfo.username || '',
|
||||
originalNickname: userInfo.nickname || '',
|
||||
hasPassword: !!(userInfo.has_password), // 使用本地缓存的has_password
|
||||
});
|
||||
}
|
||||
|
||||
// 总是从服务器获取最新信息,确保has_password字段准确
|
||||
this.fetchUserInfo();
|
||||
},
|
||||
|
||||
/**
|
||||
* 从服务器获取用户信息
|
||||
*/
|
||||
fetchUserInfo() {
|
||||
wx.showLoading({ title: '加载中...' });
|
||||
|
||||
userApi.getCurrentUser()
|
||||
.then(res => {
|
||||
if ((res.code === 1 || res.code === 200) && res.data && res.data.user) {
|
||||
const user = res.data.user;
|
||||
this.setData({
|
||||
username: user.username || '',
|
||||
nickname: user.nickname || '',
|
||||
originalUsername: user.username || '',
|
||||
originalNickname: user.nickname || '',
|
||||
hasPassword: !!(user.has_password || user.password), // 判断用户是否已设置密码
|
||||
});
|
||||
|
||||
// 更新本地存储
|
||||
AuthUtil.setUserInfo(user);
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: '获取用户信息失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
wx.showToast({
|
||||
title: '获取用户信息失败',
|
||||
icon: 'none'
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
wx.hideLoading();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户名输入变化
|
||||
*/
|
||||
onUsernameChange(e) {
|
||||
this.setData({
|
||||
username: e.detail.value,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 昵称输入变化
|
||||
*/
|
||||
onNicknameChange(e) {
|
||||
this.setData({
|
||||
nickname: e.detail.value,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 当前密码输入变化
|
||||
*/
|
||||
onOldPasswordChange(e) {
|
||||
this.setData({
|
||||
oldPassword: e.detail.value,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 新密码输入变化
|
||||
*/
|
||||
onNewPasswordChange(e) {
|
||||
this.setData({
|
||||
newPassword: e.detail.value,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认密码输入变化
|
||||
*/
|
||||
onConfirmPasswordChange(e) {
|
||||
this.setData({
|
||||
confirmPassword: e.detail.value,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 验证密码输入
|
||||
*/
|
||||
validatePassword() {
|
||||
const { hasPassword, oldPassword, newPassword, confirmPassword } = this.data;
|
||||
|
||||
// 如果没有输入新密码,说明不想修改密码
|
||||
if (!newPassword.trim() && !confirmPassword.trim()) {
|
||||
return { valid: true, changePassword: false };
|
||||
}
|
||||
|
||||
// 如果用户已有密码,必须输入当前密码
|
||||
if (hasPassword && !oldPassword.trim()) {
|
||||
wx.showToast({
|
||||
title: '请输入当前密码',
|
||||
icon: 'none'
|
||||
});
|
||||
return { valid: false, changePassword: false };
|
||||
}
|
||||
|
||||
// 新密码长度检查
|
||||
if (newPassword.length < 6 || newPassword.length > 50) {
|
||||
wx.showToast({
|
||||
title: '新密码长度必须在6-50字符之间',
|
||||
icon: 'none'
|
||||
});
|
||||
return { valid: false, changePassword: false };
|
||||
}
|
||||
|
||||
// 确认密码检查
|
||||
if (newPassword !== confirmPassword) {
|
||||
wx.showToast({
|
||||
title: '确认密码与新密码不一致',
|
||||
icon: 'none'
|
||||
});
|
||||
return { valid: false, changePassword: false };
|
||||
}
|
||||
|
||||
return { valid: true, changePassword: true };
|
||||
},
|
||||
|
||||
/**
|
||||
* 验证输入
|
||||
*/
|
||||
validateInput() {
|
||||
const { username, nickname } = this.data;
|
||||
|
||||
if (!username.trim()) {
|
||||
wx.showToast({
|
||||
title: '请输入用户名',
|
||||
icon: 'none'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
if (username.length < 3 || username.length > 50) {
|
||||
wx.showToast({
|
||||
title: '用户名长度必须在3-50字符之间',
|
||||
icon: 'none'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查用户名格式(只能包含字母和数字)
|
||||
const usernameRegex = /^[a-zA-Z0-9]+$/;
|
||||
if (!usernameRegex.test(username)) {
|
||||
wx.showToast({
|
||||
title: '用户名只能包含字母和数字',
|
||||
icon: 'none'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!nickname.trim()) {
|
||||
wx.showToast({
|
||||
title: '请输入昵称',
|
||||
icon: 'none'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nickname.length < 2 || nickname.length > 50) {
|
||||
wx.showToast({
|
||||
title: '昵称长度必须在2-50字符之间',
|
||||
icon: 'none'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* 检查是否有修改
|
||||
*/
|
||||
hasChanges() {
|
||||
const { username, nickname, originalUsername, originalNickname, newPassword } = this.data;
|
||||
return username !== originalUsername ||
|
||||
nickname !== originalNickname ||
|
||||
newPassword.trim() !== '';
|
||||
},
|
||||
|
||||
/**
|
||||
* 保存用户信息修改
|
||||
*/
|
||||
saveProfileChanges() {
|
||||
const { username, nickname } = this.data;
|
||||
|
||||
return userApi.updateProfile({
|
||||
username: username.trim(),
|
||||
nickname: nickname.trim()
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 保存密码修改
|
||||
*/
|
||||
savePasswordChanges() {
|
||||
const { hasPassword, oldPassword, newPassword, confirmPassword } = this.data;
|
||||
|
||||
return userApi.changePassword(
|
||||
hasPassword ? oldPassword : '',
|
||||
newPassword,
|
||||
confirmPassword
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* 保存修改
|
||||
*/
|
||||
handleSave() {
|
||||
if (!this.validateInput()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const passwordValidation = this.validatePassword();
|
||||
if (!passwordValidation.valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.hasChanges()) {
|
||||
wx.showToast({
|
||||
title: '没有修改内容',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.setData({ loading: true });
|
||||
|
||||
// 检查是否需要修改个人信息
|
||||
const { username, nickname, originalUsername, originalNickname } = this.data;
|
||||
const profileChanged = username !== originalUsername || nickname !== originalNickname;
|
||||
|
||||
// 需要执行的保存操作
|
||||
const saveOperations = [];
|
||||
|
||||
if (profileChanged) {
|
||||
saveOperations.push(this.saveProfileChanges());
|
||||
}
|
||||
|
||||
if (passwordValidation.changePassword) {
|
||||
saveOperations.push(this.savePasswordChanges());
|
||||
}
|
||||
|
||||
// 执行所有保存操作
|
||||
Promise.all(saveOperations)
|
||||
.then(results => {
|
||||
// 检查所有操作是否都成功(支持code: 1和code: 200)
|
||||
const allSuccess = results.every(res => res.code === 1 || res.code === 200);
|
||||
|
||||
if (allSuccess) {
|
||||
wx.showToast({
|
||||
title: '保存成功',
|
||||
icon: 'success'
|
||||
});
|
||||
|
||||
// 如果有个人信息更新,更新本地用户信息
|
||||
const profileResult = results.find(res => res.data && res.data.user);
|
||||
if (profileResult) {
|
||||
AuthUtil.setUserInfo(profileResult.data.user);
|
||||
}
|
||||
|
||||
// 延时返回上一页
|
||||
setTimeout(() => {
|
||||
wx.navigateBack();
|
||||
}, 1500);
|
||||
} else {
|
||||
// 找出失败的操作
|
||||
const failedResults = results.filter(res => res.code !== 1);
|
||||
const errorMsg = failedResults.map(res => res.msg).join(';');
|
||||
wx.showToast({
|
||||
title: errorMsg || '保存失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
wx.showToast({
|
||||
title: err.message || '保存失败,请稍后重试',
|
||||
icon: 'none'
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
this.setData({ loading: false });
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 取消修改
|
||||
*/
|
||||
handleCancel() {
|
||||
if (this.hasChanges()) {
|
||||
wx.showModal({
|
||||
title: '提示',
|
||||
content: '确定要放弃修改吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
wx.navigateBack();
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
wx.navigateBack();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面卸载时的处理
|
||||
*/
|
||||
onUnload() {
|
||||
// 如果有未保存的修改,可以在这里提示用户
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"navigationBarTitleText": "编辑个人信息",
|
||||
"navigationBarBackgroundColor": "#0052d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
<!-- 编辑个人信息页面 -->
|
||||
<view class="edit-profile-container">
|
||||
|
||||
<view class="form-section">
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="label-text">用户名</text>
|
||||
</view>
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="请输入用户名"
|
||||
value="{{username}}"
|
||||
bindinput="onUsernameChange"
|
||||
maxlength="50"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="label-text">昵称</text>
|
||||
</view>
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="请输入昵称"
|
||||
value="{{nickname}}"
|
||||
bindinput="onNicknameChange"
|
||||
maxlength="50"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="tips">
|
||||
<text class="tips-text">用户名只能包含字母和数字,长度3-50字符</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 密码修改区域 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">
|
||||
<text>修改密码</text>
|
||||
<text class="section-subtitle">{{hasPassword ? '如不修改请留空' : '微信登录用户可设置密码'}}</text>
|
||||
</view>
|
||||
|
||||
<view class="form-item" wx:if="{{hasPassword}}">
|
||||
<view class="form-label">
|
||||
<text class="label-text">当前密码</text>
|
||||
</view>
|
||||
<input
|
||||
class="form-input"
|
||||
type="password"
|
||||
placeholder="请输入当前密码"
|
||||
value="{{oldPassword}}"
|
||||
bindinput="onOldPasswordChange"
|
||||
maxlength="50"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="label-text">新密码</text>
|
||||
</view>
|
||||
<input
|
||||
class="form-input"
|
||||
type="password"
|
||||
placeholder="{{hasPassword ? '请输入新密码' : '请设置密码'}}"
|
||||
value="{{newPassword}}"
|
||||
bindinput="onNewPasswordChange"
|
||||
maxlength="50"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="label-text">确认密码</text>
|
||||
</view>
|
||||
<input
|
||||
class="form-input"
|
||||
type="password"
|
||||
placeholder="请再次输入密码确认"
|
||||
value="{{confirmPassword}}"
|
||||
bindinput="onConfirmPasswordChange"
|
||||
maxlength="50"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="tips">
|
||||
<text class="tips-text">密码长度6-50字符,建议包含字母和数字</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="button-section">
|
||||
<button
|
||||
class="save-btn {{loading ? 'loading' : ''}}"
|
||||
bindtap="handleSave"
|
||||
disabled="{{loading}}"
|
||||
>
|
||||
{{loading ? '保存中...' : '保存修改'}}
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="cancel-btn"
|
||||
bindtap="handleCancel"
|
||||
>
|
||||
取消
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
@@ -0,0 +1,128 @@
|
||||
/* pages/edit-profile/index.wxss */
|
||||
.edit-profile-container {
|
||||
padding: 30rpx;
|
||||
background-color: #f6f6f6;
|
||||
min-height: 100vh;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
.form-section {
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 30rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.form-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.label-text {
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
padding: 0 20rpx;
|
||||
border: 2rpx solid #e0e0e0;
|
||||
border-radius: 8rpx;
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
background-color: #fff;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-input:focus {
|
||||
border-color: #0052d9;
|
||||
}
|
||||
|
||||
.tips {
|
||||
margin-top: 30rpx;
|
||||
padding: 20rpx;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 8rpx;
|
||||
border-left: 6rpx solid #0052d9;
|
||||
}
|
||||
|
||||
.tips-text {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
margin-bottom: 30rpx;
|
||||
padding-bottom: 20rpx;
|
||||
border-bottom: 2rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.section-title text:first-child {
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
display: block;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.section-subtitle {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.button-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.save-btn {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
background-color: #0052d9;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 12rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.save-btn.loading {
|
||||
background-color: #ccc;
|
||||
}
|
||||
|
||||
.save-btn:not(.loading):active {
|
||||
background-color: #003ba3;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
background-color: #fff;
|
||||
color: #666;
|
||||
border: 2rpx solid #e0e0e0;
|
||||
border-radius: 12rpx;
|
||||
font-size: 32rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.cancel-btn:active {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
Reference in New Issue
Block a user