261 lines
7.1 KiB
Markdown
261 lines
7.1 KiB
Markdown
|
|
# 人设列表实现说明
|
|||
|
|
|
|||
|
|
## 📦 架构概览
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
KBAIHomeVC (人设列表容器)
|
|||
|
|
└─ UICollectionView (竖向分页滚动)
|
|||
|
|
└─ KBPersonaChatCell (每个人设占满屏)
|
|||
|
|
├─ 背景图(coverImageUrl)
|
|||
|
|
├─ 头像(avatarUrl)
|
|||
|
|
├─ 人设名称(name)
|
|||
|
|
├─ 简介(shortDesc)
|
|||
|
|
└─ UITableView (聊天记录 - 待实现)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📂 文件结构
|
|||
|
|
|
|||
|
|
### Model 层(keyBoard/Class/AiTalk/M/)
|
|||
|
|
- **KBPersonaModel.h/m**:人设模型
|
|||
|
|
- 包含:personaId、name、avatarUrl、coverImageUrl、shortDesc、introText 等
|
|||
|
|
- 扩展属性:tagsArray、isEnabled、isPublic
|
|||
|
|
|
|||
|
|
- **KBPersonaPageModel.h/m**:分页数据模型
|
|||
|
|
- 包含:records(人设数组)、total、current、pages、hasMore
|
|||
|
|
|
|||
|
|
### View 层(keyBoard/Class/AiTalk/V/)
|
|||
|
|
- **KBPersonaChatCell.h/m**:人设聊天 Cell
|
|||
|
|
- 展示:背景图、头像、名称、简介
|
|||
|
|
- 支持:预加载数据
|
|||
|
|
|
|||
|
|
### VM 层(keyBoard/Class/AiTalk/VM/)
|
|||
|
|
- **AiVM.h/m**:网络请求管理
|
|||
|
|
- 新增接口:`fetchPersonasWithPageNum:pageSize:completion:`
|
|||
|
|
- 请求地址:`POST /ai-companion/page`
|
|||
|
|
|
|||
|
|
### VC 层(keyBoard/Class/AiTalk/VC/)
|
|||
|
|
- **KBAIHomeVC.h/m**:人设列表容器
|
|||
|
|
- 功能:分页加载、竖向翻页、预加载相邻 Cell
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🔧 核心功能
|
|||
|
|
|
|||
|
|
### 1. 竖向分页滚动
|
|||
|
|
```objc
|
|||
|
|
// UICollectionView 配置
|
|||
|
|
layout.scrollDirection = UICollectionViewScrollDirectionVertical;
|
|||
|
|
layout.itemSize = [UIScreen mainScreen].bounds.size; // 每个 cell 占满屏
|
|||
|
|
_collectionView.pagingEnabled = YES; // 开启分页
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 预加载机制
|
|||
|
|
- **预加载 3 个 Cell**:上一个、当前、下一个
|
|||
|
|
- **触发时机**:滑动超过 30% 时开始预加载
|
|||
|
|
- **避免重复**:用 `preloadedIndexes` 记录已加载的索引
|
|||
|
|
|
|||
|
|
```objc
|
|||
|
|
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
|
|||
|
|
CGFloat pageHeight = scrollView.bounds.size.height;
|
|||
|
|
CGFloat offsetY = scrollView.contentOffset.y;
|
|||
|
|
NSInteger currentPage = offsetY / pageHeight;
|
|||
|
|
|
|||
|
|
// 滑动超过 30% 就预加载
|
|||
|
|
if (fmod(offsetY, pageHeight) > pageHeight * 0.3) {
|
|||
|
|
[self preloadAdjacentCellsForIndex:currentPage + 1];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 分页加载
|
|||
|
|
- **首次加载**:pageNum=1, pageSize=10
|
|||
|
|
- **加载更多**:接近底部时自动加载下一页
|
|||
|
|
- **防重复**:用 `isLoading` 标记防止重复请求
|
|||
|
|
|
|||
|
|
```objc
|
|||
|
|
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
|
|||
|
|
// 接近底部时加载更多
|
|||
|
|
if (offsetY + scrollView.bounds.size.height >= scrollView.contentSize.height - pageHeight) {
|
|||
|
|
[self loadMorePersonas];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🌐 网络请求
|
|||
|
|
|
|||
|
|
### 接口地址
|
|||
|
|
```
|
|||
|
|
POST /ai-companion/page
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 请求参数
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"pageNum": 1,
|
|||
|
|
"pageSize": 10
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 响应格式
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 0,
|
|||
|
|
"message": "success",
|
|||
|
|
"data": {
|
|||
|
|
"records": [
|
|||
|
|
{
|
|||
|
|
"id": 1,
|
|||
|
|
"name": "温柔小姐姐",
|
|||
|
|
"avatarUrl": "https://...",
|
|||
|
|
"coverImageUrl": "https://...",
|
|||
|
|
"shortDesc": "温柔体贴的聊天伙伴",
|
|||
|
|
"introText": "你好呀,今天过得怎么样?",
|
|||
|
|
"personalityTags": "温柔,体贴,善解人意",
|
|||
|
|
...
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"total": 100,
|
|||
|
|
"current": 1,
|
|||
|
|
"pages": 10
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 使用示例
|
|||
|
|
```objc
|
|||
|
|
[self.aiVM fetchPersonasWithPageNum:1
|
|||
|
|
pageSize:10
|
|||
|
|
completion:^(KBPersonaPageModel *pageModel, NSError *error) {
|
|||
|
|
if (error) {
|
|||
|
|
NSLog(@"加载失败:%@", error.localizedDescription);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[self.personas addObjectsFromArray:pageModel.records];
|
|||
|
|
self.hasMore = pageModel.hasMore;
|
|||
|
|
[self.collectionView reloadData];
|
|||
|
|
}];
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎨 UI 布局
|
|||
|
|
|
|||
|
|
### KBPersonaChatCell 布局
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────┐
|
|||
|
|
│ 背景图(coverImageUrl) │
|
|||
|
|
│ ┌─────────────────────┐ │
|
|||
|
|
│ │ 半透明遮罩(黑色 0.3) │ │
|
|||
|
|
│ │ │ │
|
|||
|
|
│ │ ┌───┐ │ │
|
|||
|
|
│ │ │头像│ │ │
|
|||
|
|
│ │ └───┘ │ │
|
|||
|
|
│ │ 人设名称 │ │
|
|||
|
|
│ │ 简短描述 │ │
|
|||
|
|
│ │ │ │
|
|||
|
|
│ │ ┌───────────────┐ │ │
|
|||
|
|
│ │ │ 聊天记录列表 │ │ │
|
|||
|
|
│ │ │ (待实现) │ │ │
|
|||
|
|
│ │ └───────────────┘ │ │
|
|||
|
|
│ └─────────────────────┘ │
|
|||
|
|
└─────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## ✅ 已完成功能
|
|||
|
|
|
|||
|
|
1. ✅ Model 层:KBPersonaModel、KBPersonaPageModel
|
|||
|
|
2. ✅ VM 层:AiVM 新增人设列表接口
|
|||
|
|
3. ✅ View 层:KBPersonaChatCell(基础 UI)
|
|||
|
|
4. ✅ VC 层:KBAIHomeVC(分页加载、竖向翻页、预加载)
|
|||
|
|
5. ✅ MJExtension 配置:JSON 自动转 Model
|
|||
|
|
6. ✅ 懒加载:所有控件使用懒加载
|
|||
|
|
7. ✅ Masonry 布局:纯代码布局
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🚧 待实现功能
|
|||
|
|
|
|||
|
|
### 1. 聊天记录展示
|
|||
|
|
- 需要后端提供 `chatId` 字段
|
|||
|
|
- 用 `chatId` 请求聊天记录接口
|
|||
|
|
- 在 `KBPersonaChatCell` 的 `tableView` 中展示聊天记录
|
|||
|
|
|
|||
|
|
### 2. 聊天功能
|
|||
|
|
- 点击输入框发送消息
|
|||
|
|
- 接收 AI 回复
|
|||
|
|
- 支持语音消息
|
|||
|
|
|
|||
|
|
### 3. 错误处理
|
|||
|
|
- 网络请求失败提示
|
|||
|
|
- 空数据占位图
|
|||
|
|
- 加载中状态
|
|||
|
|
|
|||
|
|
### 4. 性能优化
|
|||
|
|
- Cell 高度缓存
|
|||
|
|
- 图片缓存策略
|
|||
|
|
- 内存管理(清理不可见 Cell 的数据)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📝 使用方式
|
|||
|
|
|
|||
|
|
### 1. 在其他 VC 中跳转
|
|||
|
|
```objc
|
|||
|
|
KBAIHomeVC *homeVC = [[KBAIHomeVC alloc] init];
|
|||
|
|
[self.navigationController pushViewController:homeVC animated:YES];
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 作为 TabBar 的一个页面
|
|||
|
|
```objc
|
|||
|
|
KBAIHomeVC *homeVC = [[KBAIHomeVC alloc] init];
|
|||
|
|
homeVC.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"AI聊天"
|
|||
|
|
image:[UIImage imageNamed:@"tab_ai"]
|
|||
|
|
selectedImage:[UIImage imageNamed:@"tab_ai_sel"]];
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🐛 调试日志
|
|||
|
|
|
|||
|
|
### 网络请求日志
|
|||
|
|
```
|
|||
|
|
[AiVM] /ai-companion/page request: {pageNum: 1, pageSize: 10}
|
|||
|
|
[AiVM] /ai-companion/page response: {...}
|
|||
|
|
加载成功:当前 10 条,总共 100 条,还有更多:是
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 预加载日志
|
|||
|
|
```
|
|||
|
|
预加载第 0 个人设
|
|||
|
|
预加载第 1 个人设
|
|||
|
|
预加载第 2 个人设
|
|||
|
|
当前在第 1 个人设:温柔小姐姐
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📌 注意事项
|
|||
|
|
|
|||
|
|
1. **接口地址**:需要在 `KBAPI.h` 中定义 `/ai-companion/page`
|
|||
|
|
2. **图片占位图**:需要添加 `placeholder_bg` 和 `placeholder_avatar` 图片资源
|
|||
|
|
3. **线程安全**:网络回调后需要回到主线程更新 UI
|
|||
|
|
4. **内存管理**:注意使用 `weakSelf` 避免循环引用
|
|||
|
|
5. **字段兼容**:后端可能返回 `null`,已做容错处理
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎯 下一步计划
|
|||
|
|
|
|||
|
|
1. 接入真实的聊天记录接口
|
|||
|
|
2. 实现聊天输入和发送功能
|
|||
|
|
3. 优化 Cell 的聊天记录展示(使用现有的 KBChatTableView)
|
|||
|
|
4. 添加下拉刷新和上拉加载更多
|
|||
|
|
5. 添加错误提示和空数据占位图
|