新增编辑资料入口,优化用户个人信息管理体验。更新 app.json 文件以包含新页面路径,确保导航功能正常。调整样式以提升界面友好性。

This commit is contained in:
乘风
2026-02-13 17:47:13 +08:00
parent eea4a542de
commit c13ee38786
8 changed files with 584 additions and 64 deletions

View File

@@ -1,64 +1 @@
{
"pages": [
"pages/index/index",
"pages/chapters/chapters",
"pages/match/match",
"pages/my/my",
"pages/read/read",
"pages/about/about",
"pages/agreement/agreement",
"pages/privacy/privacy",
"pages/referral/referral",
"pages/purchases/purchases",
"pages/settings/settings",
"pages/search/search",
"pages/addresses/addresses",
"pages/addresses/edit","pages/withdraw-records/withdraw-records","pages/scan/scan"
],
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#000000",
"navigationBarTitleText": "Soul创业派对",
"navigationBarTextStyle": "white",
"backgroundColor": "#000000",
"navigationStyle": "custom"
},
"tabBar": {
"custom": true,
"color": "#8e8e93",
"selectedColor": "#00CED1",
"backgroundColor": "#1c1c1e",
"borderStyle": "black",
"list": [
{
"pagePath": "pages/index/index",
"text": "首页"
},
{
"pagePath": "pages/chapters/chapters",
"text": "目录"
},
{
"pagePath": "pages/match/match",
"text": "找伙伴"
},
{
"pagePath": "pages/my/my",
"text": "我的"
}
]
},
"usingComponents": {},
"__usePrivacyCheck__": true,
"permission": {
"scope.userLocation": {
"desc": "用于匹配附近的书友"
}
},
"requiredPrivateInfos": [
"getLocation"
],
"lazyCodeLoading": "requiredComponents",
"style": "v2",
"sitemapLocation": "sitemap.json"
}
{"pages":["pages/index/index","pages/chapters/chapters","pages/match/match","pages/my/my","pages/read/read","pages/about/about","pages/agreement/agreement","pages/privacy/privacy","pages/referral/referral","pages/purchases/purchases","pages/settings/settings","pages/search/search","pages/addresses/addresses","pages/addresses/edit","pages/withdraw-records/withdraw-records","pages/scan/scan","pages/profile-edit/profile-edit"],"window":{"backgroundTextStyle":"light","navigationBarBackgroundColor":"#000000","navigationBarTitleText":"Soul创业派对","navigationBarTextStyle":"white","backgroundColor":"#000000","navigationStyle":"custom"},"tabBar":{"custom":true,"color":"#8e8e93","selectedColor":"#00CED1","backgroundColor":"#1c1c1e","borderStyle":"black","list":[{"pagePath":"pages/index/index","text":"首页"},{"pagePath":"pages/chapters/chapters","text":"目录"},{"pagePath":"pages/match/match","text":"找伙伴"},{"pagePath":"pages/my/my","text":"我的"}]},"usingComponents":{},"__usePrivacyCheck__":true,"permission":{"scope.userLocation":{"desc":"用于匹配附近的书友"}},"requiredPrivateInfos":["getLocation"],"lazyCodeLoading":"requiredComponents","style":"v2","sitemapLocation":"sitemap.json"}

View File

@@ -610,6 +610,15 @@ Page({
}
},
// 跳转编辑资料页
goEditProfile() {
if (!this.data.isLoggedIn) {
this.showLogin()
return
}
wx.navigateTo({ url: '/pages/profile-edit/profile-edit' })
},
// 点击菜单
handleMenuTap(e) {
const id = e.currentTarget.dataset.id

View File

@@ -73,6 +73,12 @@
</view>
</view>
</view>
<!-- 编辑资料入口 -->
<view class="edit-profile-entry" bindtap="goEditProfile">
<text class="edit-profile-icon">✏️</text>
<text class="edit-profile-text">编辑资料</text>
</view>
<view class="stats-grid">
<view class="stat-item">

View File

@@ -95,6 +95,34 @@
white-space: nowrap;
}
/* 编辑资料入口 - 深色圆角按钮 */
.edit-profile-entry {
display: flex;
align-items: center;
justify-content: center;
gap: 16rpx;
width: 100%;
padding: 28rpx 32rpx;
margin-bottom: 24rpx;
background: rgba(255, 255, 255, 0.06);
border: 2rpx solid rgba(0, 206, 209, 0.25);
border-radius: 24rpx;
}
.edit-profile-entry:active {
background: rgba(255, 255, 255, 0.1);
}
.edit-profile-icon {
font-size: 32rpx;
}
.edit-profile-text {
font-size: 28rpx;
font-weight: 500;
color: #00CED1;
}
.card-gradient {
background: linear-gradient(135deg, #1c1c1e 0%, #2c2c2e 100%);
border-radius: 32rpx;

View File

@@ -0,0 +1,184 @@
/**
* Soul创业派对 - 编辑资料页
* 图二样式,行业/业务体量拆成两个独立输入框
*/
const app = getApp()
const MBTI_LIST = ['INTJ', 'INTP', 'ENTJ', 'ENTP', 'INFJ', 'INFP', 'ENFJ', 'ENFP', 'ISTJ', 'ISFJ', 'ESTJ', 'ESFJ', 'ISTP', 'ISFP', 'ESTP', 'ESFP']
Page({
data: {
statusBarHeight: 44,
avatar: '',
nickname: '',
mbtiList: MBTI_LIST,
mbtiIndex: 0,
mbti: '',
region: '',
industry: '',
businessVolume: '',
position: '',
mostProfitableMonth: '',
howCanHelp: ''
},
onLoad() {
this.setData({
statusBarHeight: app.globalData.statusBarHeight || 44
})
this.loadProfile()
},
loadProfile() {
const userInfo = app.globalData.userInfo || wx.getStorageSync('userInfo') || {}
const ext = wx.getStorageSync('userProfileExt') || {}
const mbti = ext.mbti || ''
const mbtiIndex = MBTI_LIST.indexOf(mbti)
this.setData({
avatar: userInfo.avatar || '',
nickname: userInfo.nickname || '',
mbti: mbti,
mbtiIndex: mbtiIndex >= 0 ? mbtiIndex : 0,
region: ext.region || '',
industry: ext.industry || '',
businessVolume: ext.businessVolume || '',
position: ext.position || '',
mostProfitableMonth: ext.mostProfitableMonth || '',
howCanHelp: ext.howCanHelp || ''
})
},
goBack() {
wx.navigateBack()
},
onNicknameInput(e) {
this.setData({ nickname: e.detail.value })
},
onMbtiChange(e) {
const i = parseInt(e.detail.value, 10)
this.setData({
mbtiIndex: i,
mbti: MBTI_LIST[i] || ''
})
},
onRegionInput(e) {
this.setData({ region: e.detail.value })
},
onIndustryInput(e) {
this.setData({ industry: e.detail.value })
},
onBusinessVolumeInput(e) {
this.setData({ businessVolume: e.detail.value })
},
onPositionInput(e) {
this.setData({ position: e.detail.value })
},
onMostProfitableMonthInput(e) {
this.setData({ mostProfitableMonth: e.detail.value })
},
onHowCanHelpInput(e) {
this.setData({ howCanHelp: e.detail.value })
},
async onChooseAvatar(e) {
const tempAvatarUrl = e.detail.avatarUrl
if (!tempAvatarUrl) return
wx.showLoading({ title: '上传中...', mask: true })
try {
const uploadRes = await new Promise((resolve, reject) => {
wx.uploadFile({
url: app.globalData.baseUrl + '/api/miniprogram/upload',
filePath: tempAvatarUrl,
name: 'file',
formData: { folder: 'avatars' },
success: (res) => {
try {
const data = JSON.parse(res.data)
if (data.success) resolve(data)
else reject(new Error(data.error || '上传失败'))
} catch (err) {
reject(new Error('解析响应失败'))
}
},
fail: (err) => reject(err)
})
})
const avatarUrl = app.globalData.baseUrl + uploadRes.data.url
this.setData({ avatar: avatarUrl })
const userInfo = app.globalData.userInfo
if (userInfo && userInfo.id) {
await app.request({
url: '/api/miniprogram/user/update',
method: 'POST',
data: { userId: userInfo.id, avatar: avatarUrl }
})
userInfo.avatar = avatarUrl
app.globalData.userInfo = userInfo
wx.setStorageSync('userInfo', userInfo)
}
wx.hideLoading()
wx.showToast({ title: '头像已更新', icon: 'success' })
} catch (e) {
wx.hideLoading()
wx.showToast({ title: e.message || '上传失败', icon: 'none' })
}
},
async saveProfile() {
const { nickname, mbti, region, industry, businessVolume, position, mostProfitableMonth, howCanHelp } = this.data
const userInfo = app.globalData.userInfo
wx.showLoading({ title: '保存中...', mask: true })
try {
if (userInfo && userInfo.id) {
const payload = { userId: userInfo.id }
if (nickname !== undefined && nickname !== userInfo.nickname) payload.nickname = nickname.trim()
if (Object.keys(payload).length > 1) {
await app.request({
url: '/api/miniprogram/user/update',
method: 'POST',
data: payload
})
if (payload.nickname !== undefined) {
userInfo.nickname = payload.nickname
app.globalData.userInfo = userInfo
wx.setStorageSync('userInfo', userInfo)
}
}
}
const ext = {
mbti: (mbti || '').trim(),
region: (region || '').trim(),
industry: (industry || '').trim(),
businessVolume: (businessVolume || '').trim(),
position: (position || '').trim(),
mostProfitableMonth: (mostProfitableMonth || '').trim(),
howCanHelp: (howCanHelp || '').trim()
}
wx.setStorageSync('userProfileExt', ext)
wx.hideLoading()
wx.showToast({ title: '保存成功', icon: 'success' })
setTimeout(() => wx.navigateBack(), 500)
} catch (e) {
wx.hideLoading()
wx.showToast({ title: e.message || '保存失败', icon: 'none' })
}
}
})

View File

@@ -0,0 +1,4 @@
{
"usingComponents": {},
"navigationStyle": "custom"
}

View File

@@ -0,0 +1,125 @@
<!-- 编辑资料页 - 图二样式,行业/业务体量拆成两个输入框 -->
<view class="page">
<view class="nav-bar" style="padding-top: {{statusBarHeight}}px;">
<view class="nav-back" bindtap="goBack">
<text class="back-icon"></text>
</view>
<text class="nav-title">编辑资料</text>
<view class="nav-placeholder"></view>
</view>
<view class="nav-placeholder-bar" style="height: {{statusBarHeight + 44}}px;"></view>
<view class="content">
<!-- 头像 -->
<view class="avatar-section">
<button class="avatar-btn" open-type="chooseAvatar" bindchooseavatar="onChooseAvatar">
<image class="avatar-img" wx:if="{{avatar}}" src="{{avatar}}" mode="aspectFill"/>
<text class="avatar-text" wx:else>{{nickname[0] || '头'}}</text>
</button>
<button class="avatar-change-btn" open-type="chooseAvatar" bindchooseavatar="onChooseAvatar">更换头像</button>
</view>
<!-- 昵称 -->
<view class="form-group">
<text class="form-label">昵称</text>
<input
class="form-input"
value="{{nickname}}"
placeholder="点击输入昵称"
placeholder-class="form-placeholder"
bindinput="onNicknameInput"
/>
</view>
<!-- MBTI 与 地区 并排 -->
<view class="form-row">
<view class="form-group half">
<text class="form-label">MBTI</text>
<picker mode="selector" range="{{mbtiList}}" value="{{mbtiIndex}}" bindchange="onMbtiChange">
<view class="form-picker">
<text class="{{mbti ? '' : 'placeholder'}}">{{mbti || '请选择'}}</text>
<text class="picker-arrow">▼</text>
</view>
</picker>
</view>
<view class="form-group half">
<text class="form-label">地区</text>
<view class="form-input-wrap">
<text class="region-icon">📍</text>
<input
class="form-input form-input-inline"
value="{{region}}"
placeholder="杭州 · 余杭区"
placeholder-class="form-placeholder"
bindinput="onRegionInput"
/>
</view>
</view>
</view>
<!-- 行业(独立输入框) -->
<view class="form-group">
<text class="form-label">行业</text>
<input
class="form-input"
value="{{industry}}"
placeholder="如电商、SaaS"
placeholder-class="form-placeholder"
bindinput="onIndustryInput"
/>
</view>
<!-- 业务体量(独立输入框) -->
<view class="form-group">
<text class="form-label">业务体量</text>
<input
class="form-input"
value="{{businessVolume}}"
placeholder="如年GMV 5000W+"
placeholder-class="form-placeholder"
bindinput="onBusinessVolumeInput"
/>
</view>
<!-- 职位 -->
<view class="form-group">
<text class="form-label">职位</text>
<input
class="form-input"
value="{{position}}"
placeholder="如:联合创始人"
placeholder-class="form-placeholder"
bindinput="onPositionInput"
/>
</view>
<!-- 你最赚钱的一个月做的是什么 -->
<view class="form-group">
<text class="form-label">你最赚钱的一个月做的是什么</text>
<textarea
class="form-textarea"
value="{{mostProfitableMonth}}"
placeholder="请简要描述"
placeholder-class="form-placeholder"
bindinput="onMostProfitableMonthInput"
maxlength="500"
/>
</view>
<!-- 我能帮到大家什么 -->
<view class="form-group">
<text class="form-label">我能帮到大家什么</text>
<textarea
class="form-textarea"
value="{{howCanHelp}}"
placeholder="请简要描述"
placeholder-class="form-placeholder"
bindinput="onHowCanHelpInput"
maxlength="500"
/>
</view>
<view class="save-btn" bindtap="saveProfile">保存</view>
<view class="bottom-space"></view>
</view>
</view>

View File

@@ -0,0 +1,227 @@
/* 编辑资料页 - 深色主题 */
.page {
min-height: 100vh;
background: #000;
padding-bottom: 64rpx;
}
.nav-bar {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
background: rgba(0, 0, 0, 0.9);
backdrop-filter: blur(40rpx);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 32rpx;
height: 88rpx;
}
.nav-back {
width: 64rpx;
height: 64rpx;
background: #1c1c1e;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.back-icon {
font-size: 40rpx;
color: rgba(255, 255, 255, 0.6);
font-weight: 300;
}
.nav-title {
font-size: 34rpx;
font-weight: 600;
color: #fff;
}
.nav-placeholder {
width: 64rpx;
}
.nav-placeholder-bar {
width: 100%;
}
.content {
padding: 32rpx;
}
/* 头像区域 */
.avatar-section {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 48rpx;
}
.avatar-btn {
width: 160rpx;
height: 160rpx;
padding: 0;
margin: 0;
background: transparent;
border: none;
border-radius: 50%;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
.avatar-btn::after {
border: none;
}
.avatar-img {
width: 160rpx;
height: 160rpx;
border-radius: 50%;
border: 4rpx solid rgba(0, 206, 209, 0.3);
object-fit: cover;
}
.avatar-text {
width: 160rpx;
height: 160rpx;
border-radius: 50%;
border: 4rpx solid rgba(0, 206, 209, 0.3);
background: rgba(0, 206, 209, 0.15);
display: flex;
align-items: center;
justify-content: center;
font-size: 56rpx;
font-weight: 600;
color: #00CED1;
}
.avatar-change-btn {
margin-top: 16rpx;
padding: 0;
margin-left: 0;
margin-right: 0;
background: transparent;
border: none;
font-size: 26rpx;
color: #00CED1;
line-height: normal;
}
.avatar-change-btn::after {
border: none;
}
/* 表单项 */
.form-group {
margin-bottom: 32rpx;
}
.form-label {
display: block;
font-size: 26rpx;
color: rgba(255, 255, 255, 0.7);
margin-bottom: 12rpx;
}
.form-input,
.form-picker {
width: 100%;
padding: 24rpx;
background: rgba(255, 255, 255, 0.06);
border: 2rpx solid rgba(0, 206, 209, 0.25);
border-radius: 16rpx;
font-size: 28rpx;
color: #fff;
box-sizing: border-box;
}
.form-placeholder {
color: rgba(255, 255, 255, 0.35);
}
.form-picker {
display: flex;
align-items: center;
gap: 12rpx;
}
.form-picker .placeholder {
color: rgba(255, 255, 255, 0.35);
}
.form-input-wrap {
display: flex;
align-items: center;
gap: 12rpx;
width: 100%;
padding: 0 24rpx;
background: rgba(255, 255, 255, 0.06);
border: 2rpx solid rgba(0, 206, 209, 0.25);
border-radius: 16rpx;
box-sizing: border-box;
}
.form-input-inline {
flex: 1;
min-width: 0;
}
.region-icon {
font-size: 28rpx;
flex-shrink: 0;
}
.picker-arrow {
margin-left: auto;
font-size: 20rpx;
color: rgba(255, 255, 255, 0.4);
}
/* MBTI 与 地区 并排 */
.form-row {
display: flex;
gap: 24rpx;
}
.form-group.half {
flex: 1;
min-width: 0;
}
.form-textarea {
width: 100%;
min-height: 160rpx;
padding: 24rpx;
background: rgba(255, 255, 255, 0.06);
border: 2rpx solid rgba(0, 206, 209, 0.25);
border-radius: 16rpx;
font-size: 28rpx;
color: #fff;
box-sizing: border-box;
}
.save-btn {
margin-top: 48rpx;
padding: 28rpx;
background: linear-gradient(135deg, #00CED1 0%, #20B2AA 100%);
color: #000;
font-size: 30rpx;
font-weight: 600;
text-align: center;
border-radius: 24rpx;
}
.save-btn:active {
opacity: 0.9;
}
.bottom-space {
height: 80rpx;
}