Files
happy-life-star/docs/superpowers/specs/2026-06-03-user-profile-real-data-design.md
T

8.6 KiB
Raw Blame History

小程序用户信息去写死 + 编辑资料保存生效 — 设计文档

背景

小程序"人生轨迹"页和"编辑资料"页存在大量硬编码的用户信息(昵称、星座、MBTI、职业、爱好、示例事件等)。即使用户已登录并设置了真实资料,页面仍展示写死的数据。同时,编辑资料页中的 city/industry/company/personalityTags/birthday 字段因后端 API 不支持而无法真正保存,导致"保存成功但回显丢失"。

目标

  1. 人生轨迹页(RecordView.vue)必须展示当前登录用户的真实资料,去除一切写死数据。
  2. 编辑资料页(onboarding/index.vue)必须能成功保存、更新、回显用户信息。
  3. 后端扩展 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. 实体类扩展

文件:backend-single/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 个字段:

  • backend-single/src/main/java/com/emotion/dto/request/userprofile/UserProfileCreateRequest.java
  • backend-single/src/main/java/com/emotion/dto/request/userprofile/UserProfileUpdateRequest.java
  • backend-single/src/main/java/com/emotion/dto/response/userprofile/UserProfileResponse.java

UserProfileResponse 中的 birthday 使用 @JsonFormat(pattern = "yyyy-MM-dd") 注解,与现有日期字段保持一致。

4. Service 层

文件:backend-single/src/main/java/com/emotion/service/impl/UserProfileServiceImpl.java

无需改动。BeanUtils.copyPropertiesBeanUtil.copyProperties(..., CopyOptions.create().setIgnoreNullValue(true)) 会自动映射同名字段。

前端改动

1. 人生轨迹页(mini-program/src/pages/main/RecordView.vue

移除示例事件:

  • 删除 sampleEvents 数组(4 条写死的人生事件数据)。
  • events computed 逻辑改为:
    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' ''

空值显示优化:

  • birthdayDisplay computed:空值时返回 "请选择生日"
  • 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 语句
backend-single/.../entity/UserProfile.java 修改 新增 5 个字段
backend-single/.../request/.../UserProfileCreateRequest.java 修改 新增 5 个字段
backend-single/.../request/.../UserProfileUpdateRequest.java 修改 新增 5 个字段
backend-single/.../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 添加已存在列会报错。本次为全新列名,安全。若生产环境已存在(极小概率),需人工确认。

测试验证点

  1. 新用户首次编辑资料,所有字段留空,保存成功,回显为空。
  2. 填写城市、行业、公司、性格标签、生日后保存,重新进入编辑页,数据正确回显。
  3. 人生轨迹页未设置资料时,用户信息和爱好显示"未设置"或留空,不展示任何写死数据。
  4. 人生轨迹页无事件时,显示"还没有人生轨迹"空状态,不展示 sampleEvents。
  5. 已有用户(老数据)登录后,页面正常展示,无报错。