8.5 KiB
小程序用户信息去写死 + 编辑资料保存生效 — 设计文档
背景
小程序"人生轨迹"页和"编辑资料"页存在大量硬编码的用户信息(昵称、星座、MBTI、职业、爱好、示例事件等)。即使用户已登录并设置了真实资料,页面仍展示写死的数据。同时,编辑资料页中的 city/industry/company/personalityTags/birthday 字段因后端 API 不支持而无法真正保存,导致"保存成功但回显丢失"。
目标
- 人生轨迹页(
RecordView.vue)必须展示当前登录用户的真实资料,去除一切写死数据。 - 编辑资料页(
onboarding/index.vue)必须能成功保存、更新、回显用户信息。 - 后端扩展
t_user_profile表和相关 DTO,支持前端已有的city/industry/company/personalityTags/birthday字段。
非目标
- 个人中心页(
MineView.vue)的修复不在本次任务范围内(已有独立任务)。 - 不修改 UI 视觉风格,只改数据绑定和默认值策略。
架构与数据流
编辑资料页 (onboarding/index.vue)
↓ form 数据
前端 userProfileService.transformToBackendFormat
↓ 新增 city/industry/company/personalityTags/birthday
后端 UserProfileController → UserProfileService
↓
数据库 t_user_profile (新增5个字段)
↓
后端返回 UserProfileResponse (含新增字段)
↓
前端 userProfileService.transformToFrontendFormat
↓ store.userProfile
人生轨迹页 (RecordView.vue) / 编辑资料页回显
后端改动
1. 数据库迁移
文件:sql/emotion_museum_ddl.sql(追加)
-- 用户档案扩展字段:城市、行业、公司、性格标签、生日
alter table emotion_museum.t_user_profile
add city varchar(100) null comment '所在城市',
add industry varchar(100) null comment '行业',
add company varchar(200) null comment '公司',
add personality_tags json null comment '性格标签列表',
add birthday date null comment '生日';
2. 实体类扩展
文件:server/src/main/java/com/emotion/entity/UserProfile.java
新增字段(与数据库列名通过 @TableField 映射):
| 字段名 | 类型 | 数据库列 | 说明 |
|---|---|---|---|
| city | String | city | 所在城市 |
| industry | String | industry | 行业 |
| company | String | company | 公司 |
| personalityTags | String | personality_tags | 性格标签 JSON 字符串 |
| birthday | LocalDate | birthday | 生日 |
3. DTO 扩展
以下三个文件新增相同 5 个字段:
server/src/main/java/com/emotion/dto/request/userprofile/UserProfileCreateRequest.javaserver/src/main/java/com/emotion/dto/request/userprofile/UserProfileUpdateRequest.javaserver/src/main/java/com/emotion/dto/response/userprofile/UserProfileResponse.java
UserProfileResponse 中的 birthday 使用 @JsonFormat(pattern = "yyyy-MM-dd") 注解,与现有日期字段保持一致。
4. Service 层
文件:server/src/main/java/com/emotion/service/impl/UserProfileServiceImpl.java
无需改动。BeanUtils.copyProperties 和 BeanUtil.copyProperties(..., CopyOptions.create().setIgnoreNullValue(true)) 会自动映射同名字段。
前端改动
1. 人生轨迹页(mini-program/src/pages/main/RecordView.vue)
移除示例事件:
- 删除
sampleEvents数组(4 条写死的人生事件数据)。 eventscomputed 逻辑改为:const events = computed(() => store.events || [])- 空事件时保留现有空状态 UI("还没有人生轨迹")。
移除硬编码默认值:
| 原代码 | 修改后 |
|---|---|
profile.nickname || 'Zoey' |
profile.nickname || '' |
profile.zodiac || '巨蟹座' |
profile.zodiac || '' |
profile.mbti || 'ENTJ' |
profile.mbti || '' |
profile.profession || '产品经理' |
profile.profession || '' |
heroTags 默认 ['阅读', '旅行', '音乐', '创作'] |
[] |
avatar 计算中的默认 'Zoey' |
保留 'User' 作为 Dicebear seed 的兜底(这是头像生成种子,非展示名称) |
空值 UI 处理:
- 昵称空时,profile-info 区域不显示名称,但保留"正在成为更清晰的自己"作为固定标语(非用户数据)。
- 星座/MBTI/职业空时,对应 meta-item 的
meta-value显示"未设置"。 - 爱好空时,
hobby-text显示"未设置"。
2. 编辑资料页(mini-program/src/pages/onboarding/index.vue)
syncFromStore() 去除硬编码默认值:
原逻辑在 source 为空时回退到大量硬编码值,改为全部回退到空值/空数组:
| 字段 | 原默认值 | 新默认值 |
|---|---|---|
| nickname | '' |
''(不变) |
| gender | '女' |
'' |
| zodiac | '巨蟹座' |
'' |
| mbti | 'ENTJ' |
'' |
| profession | '产品经理' |
'' |
| city | '上海市' |
'' |
| industry | '互联网' |
'' |
| company | '' |
''(不变) |
| personalityTags | ['理性', '乐观', ...] |
[] |
| hobbies | ['阅读', '旅行', '音乐'] |
[] |
| future.ideal | 长文本默认 | '' |
| birthday | '1998-06-18' |
'' |
空值显示优化:
birthdayDisplaycomputed:空值时返回"请选择生日"。avatarUrl:空昵称时保留默认 Dicebear 头像(seed 用"User"),仅作为头像生成参数,不展示给用户。
保存逻辑:
saveProfile逻辑不变,继续调用store.updateRegistration()和store.saveUserProfile()。- 由于后端已扩展字段,所有字段均可正确保存。
3. 前端 Service 扩展(mini-program/src/services/userProfile.js)
transformToBackendFormat 增加:
return {
// ... 原有字段 ...
city: frontendData.city || null,
industry: frontendData.industry || null,
company: frontendData.company || null,
personalityTags: Array.isArray(frontendData.personalityTags)
? JSON.stringify(frontendData.personalityTags)
: frontendData.personalityTags,
birthday: frontendData.birthday || null
}
transformToFrontendFormat 增加:
return {
// ... 原有字段 ...
city: backendData.city || '',
industry: backendData.industry || '',
company: backendData.company || '',
personalityTags: backendData.personalityTags
? (typeof backendData.personalityTags === 'string'
? JSON.parse(backendData.personalityTags)
: backendData.personalityTags)
: [],
birthday: backendData.birthday || ''
}
4. Store 扩展(mini-program/src/stores/app.js)
registrationData 初始结构增加:
registrationData: {
// ... 原有字段 ...
city: '',
industry: '',
company: '',
personalityTags: [],
birthday: ''
}
文件变更清单
| 文件 | 改动类型 | 说明 |
|---|---|---|
sql/emotion_museum_ddl.sql |
追加 | 5 个 ALTER TABLE 语句 |
server/.../entity/UserProfile.java |
修改 | 新增 5 个字段 |
server/.../request/.../UserProfileCreateRequest.java |
修改 | 新增 5 个字段 |
server/.../request/.../UserProfileUpdateRequest.java |
修改 | 新增 5 个字段 |
server/.../response/.../UserProfileResponse.java |
修改 | 新增 5 个字段 |
mini-program/src/services/userProfile.js |
修改 | 双向转换增加 5 个字段 |
mini-program/src/stores/app.js |
修改 | registrationData 扩展 |
mini-program/src/pages/main/RecordView.vue |
修改 | 去除写死默认值和 sampleEvents |
mini-program/src/pages/onboarding/index.vue |
修改 | 去除硬编码默认值,优化空值展示 |
错误处理
- 保存失败:
saveProfile已有uni.showToast({ title: res.error || '保存失败' }),无需额外改动。 - 后端字段新增后老数据兼容:新增字段均为
NULL,老数据读取时前端transformToFrontendFormat会转为空字符串/空数组,不影响现有逻辑。 - 数据库列已存在:ALTER TABLE 添加已存在列会报错。本次为全新列名,安全。若生产环境已存在(极小概率),需人工确认。
测试验证点
- 新用户首次编辑资料,所有字段留空,保存成功,回显为空。
- 填写城市、行业、公司、性格标签、生日后保存,重新进入编辑页,数据正确回显。
- 人生轨迹页未设置资料时,用户信息和爱好显示"未设置"或留空,不展示任何写死数据。
- 人生轨迹页无事件时,显示"还没有人生轨迹"空状态,不展示 sampleEvents。
- 已有用户(老数据)登录后,页面正常展示,无报错。