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

211 lines
8.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 小程序用户信息去写死 + 编辑资料保存生效 — 设计文档
## 背景
小程序"人生轨迹"页和"编辑资料"页存在大量硬编码的用户信息(昵称、星座、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`(追加)
```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.java`
- `server/src/main/java/com/emotion/dto/request/userprofile/UserProfileUpdateRequest.java`
- `server/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 条写死的人生事件数据)。
- `events` computed 逻辑改为:
```js
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` 增加:**
```js
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` 增加:**
```js
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` 初始结构增加:
```js
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 添加已存在列会报错。本次为全新列名,安全。若生产环境已存在(极小概率),需人工确认。
## 测试验证点
1. 新用户首次编辑资料,所有字段留空,保存成功,回显为空。
2. 填写城市、行业、公司、性格标签、生日后保存,重新进入编辑页,数据正确回显。
3. 人生轨迹页未设置资料时,用户信息和爱好显示"未设置"或留空,不展示任何写死数据。
4. 人生轨迹页无事件时,显示"还没有人生轨迹"空状态,不展示 sampleEvents。
5. 已有用户(老数据)登录后,页面正常展示,无报错。