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

## 背景

小程序"人生轨迹"页和"编辑资料"页存在大量硬编码的用户信息（昵称、星座、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. 已有用户（老数据）登录后，页面正常展示，无报错。
