添加个人主页

This commit is contained in:
2026-01-29 16:03:21 +08:00
parent 766c62f3c0
commit 26096abbcc
6 changed files with 155 additions and 27 deletions

View File

@@ -156,6 +156,7 @@
048FFD3F2F29F600005D62AE /* KBChattedCompanionModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD3E2F29F600005D62AE /* KBChattedCompanionModel.m */; }; 048FFD3F2F29F600005D62AE /* KBChattedCompanionModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD3E2F29F600005D62AE /* KBChattedCompanionModel.m */; };
048FFD422F29F700005D62AE /* KBChatSessionResetModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD412F29F700005D62AE /* KBChatSessionResetModel.m */; }; 048FFD422F29F700005D62AE /* KBChatSessionResetModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD412F29F700005D62AE /* KBChatSessionResetModel.m */; };
048FFD472F2B45D4005D62AE /* AIPersonInfoVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD462F2B45D4005D62AE /* AIPersonInfoVC.m */; }; 048FFD472F2B45D4005D62AE /* AIPersonInfoVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD462F2B45D4005D62AE /* AIPersonInfoVC.m */; };
048FFD4A2F2B4AE4005D62AE /* KBAICompanionDetailModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD492F2B4AE4005D62AE /* KBAICompanionDetailModel.m */; };
0498BD622EDFFC12006CC1D5 /* KBMyVM.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD612EDFFC12006CC1D5 /* KBMyVM.m */; }; 0498BD622EDFFC12006CC1D5 /* KBMyVM.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD612EDFFC12006CC1D5 /* KBMyVM.m */; };
0498BD652EE0116D006CC1D5 /* KBEmailLoginVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD642EE0116D006CC1D5 /* KBEmailLoginVC.m */; }; 0498BD652EE0116D006CC1D5 /* KBEmailLoginVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD642EE0116D006CC1D5 /* KBEmailLoginVC.m */; };
0498BD682EE01180006CC1D5 /* KBEmailRegistVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD672EE01180006CC1D5 /* KBEmailRegistVC.m */; }; 0498BD682EE01180006CC1D5 /* KBEmailRegistVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD672EE01180006CC1D5 /* KBEmailRegistVC.m */; };
@@ -580,6 +581,8 @@
048FFD412F29F700005D62AE /* KBChatSessionResetModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBChatSessionResetModel.m; sourceTree = "<group>"; }; 048FFD412F29F700005D62AE /* KBChatSessionResetModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBChatSessionResetModel.m; sourceTree = "<group>"; };
048FFD452F2B45D4005D62AE /* AIPersonInfoVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AIPersonInfoVC.h; sourceTree = "<group>"; }; 048FFD452F2B45D4005D62AE /* AIPersonInfoVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AIPersonInfoVC.h; sourceTree = "<group>"; };
048FFD462F2B45D4005D62AE /* AIPersonInfoVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AIPersonInfoVC.m; sourceTree = "<group>"; }; 048FFD462F2B45D4005D62AE /* AIPersonInfoVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AIPersonInfoVC.m; sourceTree = "<group>"; };
048FFD482F2B4AE4005D62AE /* KBAICompanionDetailModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAICompanionDetailModel.h; sourceTree = "<group>"; };
048FFD492F2B4AE4005D62AE /* KBAICompanionDetailModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBAICompanionDetailModel.m; sourceTree = "<group>"; };
0498BD5E2EDF2157006CC1D5 /* KBBizCode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBBizCode.h; sourceTree = "<group>"; }; 0498BD5E2EDF2157006CC1D5 /* KBBizCode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBBizCode.h; sourceTree = "<group>"; };
0498BD602EDFFC12006CC1D5 /* KBMyVM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBMyVM.h; sourceTree = "<group>"; }; 0498BD602EDFFC12006CC1D5 /* KBMyVM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBMyVM.h; sourceTree = "<group>"; };
0498BD612EDFFC12006CC1D5 /* KBMyVM.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBMyVM.m; sourceTree = "<group>"; }; 0498BD612EDFFC12006CC1D5 /* KBMyVM.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBMyVM.m; sourceTree = "<group>"; };
@@ -1049,6 +1052,8 @@
048FFD412F29F700005D62AE /* KBChatSessionResetModel.m */, 048FFD412F29F700005D62AE /* KBChatSessionResetModel.m */,
048FFD372F2A24C5005D62AE /* KBAIChatMessageCacheManager.h */, 048FFD372F2A24C5005D62AE /* KBAIChatMessageCacheManager.h */,
048FFD382F2A24C5005D62AE /* KBAIChatMessageCacheManager.m */, 048FFD382F2A24C5005D62AE /* KBAIChatMessageCacheManager.m */,
048FFD482F2B4AE4005D62AE /* KBAICompanionDetailModel.h */,
048FFD492F2B4AE4005D62AE /* KBAICompanionDetailModel.m */,
); );
path = M; path = M;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -2409,6 +2414,7 @@
0450AC102EF11E4400B6AF06 /* StoreKitDelegate.swift in Sources */, 0450AC102EF11E4400B6AF06 /* StoreKitDelegate.swift in Sources */,
0450AC112EF11E4400B6AF06 /* StoreKitService.swift in Sources */, 0450AC112EF11E4400B6AF06 /* StoreKitService.swift in Sources */,
0450AC122EF11E4400B6AF06 /* TransactionConverter.swift in Sources */, 0450AC122EF11E4400B6AF06 /* TransactionConverter.swift in Sources */,
048FFD4A2F2B4AE4005D62AE /* KBAICompanionDetailModel.m in Sources */,
0450AC132EF11E4400B6AF06 /* SubscriptionConverter.swift in Sources */, 0450AC132EF11E4400B6AF06 /* SubscriptionConverter.swift in Sources */,
0450AC142EF11E4400B6AF06 /* ProductConverter.swift in Sources */, 0450AC142EF11E4400B6AF06 /* ProductConverter.swift in Sources */,
0450AC152EF11E4400B6AF06 /* TransactionHistory.swift in Sources */, 0450AC152EF11E4400B6AF06 /* TransactionHistory.swift in Sources */,

View File

@@ -15,7 +15,7 @@
#import <Masonry/Masonry.h> #import <Masonry/Masonry.h>
#import <SDWebImage/SDWebImage.h> #import <SDWebImage/SDWebImage.h>
#import <LSTPopView/LSTPopView.h> #import <LSTPopView/LSTPopView.h>
#import "AIPersonInfoVC.h"
/// ///
static NSString * const KBChatSessionDidResetNotification = @"KBChatSessionDidResetNotification"; static NSString * const KBChatSessionDidResetNotification = @"KBChatSessionDidResetNotification";
@@ -549,6 +549,11 @@ static NSString * const KBChatSessionDidResetNotification = @"KBChatSessionDidRe
_avatarImageView.layer.borderWidth = 3; _avatarImageView.layer.borderWidth = 3;
_avatarImageView.layer.borderColor = [UIColor whiteColor].CGColor; _avatarImageView.layer.borderColor = [UIColor whiteColor].CGColor;
_avatarImageView.clipsToBounds = YES; _avatarImageView.clipsToBounds = YES;
_avatarImageView.userInteractionEnabled = YES;
//
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(avatarTapped)];
[_avatarImageView addGestureRecognizer:tap];
} }
return _avatarImageView; return _avatarImageView;
} }
@@ -628,6 +633,19 @@ static NSString * const KBChatSessionDidResetNotification = @"KBChatSessionDidRe
#pragma mark - Button Actions #pragma mark - Button Actions
- (void)avatarTapped {
NSLog(@"[KBPersonaChatCell] 头像点击,跳转到人设详情页");
if (self.persona.personaId <= 0) {
NSLog(@"[KBPersonaChatCell] personaId 无效,取消跳转");
return;
}
AIPersonInfoVC *vc = [[AIPersonInfoVC alloc] init];
vc.companionId = self.persona.personaId;
[KB_CURRENT_NAV pushViewController:vc animated:YES];
}
- (void)commentButtonTapped:(KBImagePositionButton *)sender { - (void)commentButtonTapped:(KBImagePositionButton *)sender {
NSLog(@"[KBPersonaChatCell] 评论按钮点击"); NSLog(@"[KBPersonaChatCell] 评论按钮点击");

View File

@@ -11,14 +11,8 @@ NS_ASSUME_NONNULL_BEGIN
@interface AIPersonInfoVC : BaseViewController @interface AIPersonInfoVC : BaseViewController
/// 背景图 URL /// AI 角色 ID必传用于请求详情
@property (nonatomic, copy) NSString *backgroundImageURL; @property (nonatomic, assign) NSInteger companionId;
/// 人设名称
@property (nonatomic, copy) NSString *personaName;
/// 人设介绍
@property (nonatomic, copy) NSString *personaIntroduction;
/// 人设 ID用于举报等
@property (nonatomic, assign) NSInteger personaId;
@end @end

View File

@@ -6,7 +6,9 @@
// //
#import "AIPersonInfoVC.h" #import "AIPersonInfoVC.h"
#import "AIReportVC.h" //#import "AIReportVC.h"
#import "AiVM.h"
#import "KBAICompanionDetailModel.h"
#import <SDWebImage/SDWebImage.h> #import <SDWebImage/SDWebImage.h>
@interface AIPersonInfoVC () @interface AIPersonInfoVC ()
@@ -29,6 +31,10 @@
@property (nonatomic, strong) UILabel *introLabel; @property (nonatomic, strong) UILabel *introLabel;
/// Go Chatting /// Go Chatting
@property (nonatomic, strong) UIButton *goChatButton; @property (nonatomic, strong) UIButton *goChatButton;
/// AiVM
@property (nonatomic, strong) AiVM *aiVM;
///
@property (nonatomic, strong) KBAICompanionDetailModel *detailModel;
@end @end
@@ -41,12 +47,13 @@
self.kb_navView.hidden = YES; self.kb_navView.hidden = YES;
self.view.backgroundColor = [UIColor blackColor]; self.view.backgroundColor = [UIColor blackColor];
self.aiVM = [[AiVM alloc] init];
/// 1 /// 1
[self setupUI]; [self setupUI];
/// 2 /// 2
[self bindActions]; [self bindActions];
/// 3 /// 3
[self loadData]; [self loadData];
} }
@@ -133,20 +140,55 @@
[self.view addGestureRecognizer:tap]; [self.view addGestureRecognizer:tap];
} }
#pragma mark - 3 #pragma mark - 3
- (void)loadData { - (void)loadData {
// if (self.companionId <= 0) {
if (self.backgroundImageURL.length > 0) { NSLog(@"[AIPersonInfoVC] companionId 无效");
[self.backgroundImageView sd_setImageWithURL:[NSURL URLWithString:self.backgroundImageURL] return;
}
[KBHUD show];
__weak typeof(self) weakSelf = self;
[self.aiVM fetchCompanionDetailWithCompanionId:self.companionId
completion:^(KBAICompanionDetailModel * _Nullable detail, NSError * _Nullable error) {
dispatch_async(dispatch_get_main_queue(), ^{
[KBHUD dismiss];
if (error) {
NSLog(@"[AIPersonInfoVC] 获取详情失败: %@", error.localizedDescription);
[KBHUD showError:error.localizedDescription];
return;
}
if (!detail) {
NSLog(@"[AIPersonInfoVC] 详情数据为空");
return;
}
weakSelf.detailModel = detail;
[weakSelf updateUI];
});
}];
}
#pragma mark - 4 UI
- (void)updateUI {
// 使 coverImageUrl avatarUrl
NSString *imageUrl = self.detailModel.coverImageUrl.length > 0 ? self.detailModel.coverImageUrl : self.detailModel.avatarUrl;
if (imageUrl.length > 0) {
[self.backgroundImageView sd_setImageWithURL:[NSURL URLWithString:imageUrl]
placeholderImage:KBPlaceholderImage]; placeholderImage:KBPlaceholderImage];
} }
// //
self.nameLabel.text = self.personaName ?: @""; self.nameLabel.text = self.detailModel.name ?: @"";
// // 使 introText shortDesc
self.introLabel.text = self.personaIntroduction ?: @""; NSString *intro = self.detailModel.introText.length > 0 ? self.detailModel.introText : self.detailModel.shortDesc;
self.introLabel.text = intro ?: @"";
} }
#pragma mark - Actions #pragma mark - Actions
@@ -162,9 +204,9 @@
- (void)reportButtonTapped { - (void)reportButtonTapped {
self.reportPopView.hidden = YES; self.reportPopView.hidden = YES;
AIReportVC *vc = [[AIReportVC alloc] init]; // AIReportVC *vc = [[AIReportVC alloc] init];
vc.personaId = self.personaId; // vc.personaId = self.companionId;
[self.navigationController pushViewController:vc animated:YES]; // [self.navigationController pushViewController:vc animated:YES];
} }
- (void)goChatButtonTapped { - (void)goChatButtonTapped {
@@ -228,9 +270,11 @@
- (UIButton *)moreButton { - (UIButton *)moreButton {
if (!_moreButton) { if (!_moreButton) {
_moreButton = [UIButton buttonWithType:UIButtonTypeCustom]; _moreButton = [UIButton buttonWithType:UIButtonTypeCustom];
// 使 // 使
[_moreButton setImage:[UIImage imageNamed:@"ai_more_icon"] forState:UIControlStateNormal]; UIImage *moreImage = [UIImage imageNamed:@"ai_more_icon"];
if (![UIImage imageNamed:@"ai_more_icon"]) { if (moreImage) {
[_moreButton setImage:moreImage forState:UIControlStateNormal];
} else {
// 使 // 使
[_moreButton setTitle:@"•••" forState:UIControlStateNormal]; [_moreButton setTitle:@"•••" forState:UIControlStateNormal];
[_moreButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; [_moreButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
@@ -250,13 +294,16 @@
// //
UIButton *reportBtn = [UIButton buttonWithType:UIButtonTypeCustom]; UIButton *reportBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[reportBtn setImage:[UIImage imageNamed:@"ai_report_icon"] forState:UIControlStateNormal]; UIImage *reportIcon = [UIImage imageNamed:@"ai_report_icon"];
if (reportIcon) {
[reportBtn setImage:reportIcon forState:UIControlStateNormal];
reportBtn.imageEdgeInsets = UIEdgeInsetsMake(0, 8, 0, 0);
reportBtn.titleEdgeInsets = UIEdgeInsetsMake(0, 16, 0, 0);
}
[reportBtn setTitle:KBLocalized(@"Report") forState:UIControlStateNormal]; [reportBtn setTitle:KBLocalized(@"Report") forState:UIControlStateNormal];
[reportBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; [reportBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
reportBtn.titleLabel.font = [UIFont systemFontOfSize:14]; reportBtn.titleLabel.font = [UIFont systemFontOfSize:14];
reportBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; reportBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
reportBtn.imageEdgeInsets = UIEdgeInsetsMake(0, 8, 0, 0);
reportBtn.titleEdgeInsets = UIEdgeInsetsMake(0, 16, 0, 0);
[reportBtn addTarget:self action:@selector(reportButtonTapped) forControlEvents:UIControlEventTouchUpInside]; [reportBtn addTarget:self action:@selector(reportButtonTapped) forControlEvents:UIControlEventTouchUpInside];
[_reportPopView addSubview:reportBtn]; [_reportPopView addSubview:reportBtn];

View File

@@ -164,6 +164,14 @@ typedef void (^AiVMSpeechTranscribeCompletion)(KBAiSpeechTranscribeResponse *_Nu
- (void)resetChatSessionWithCompanionId:(NSInteger)companionId - (void)resetChatSessionWithCompanionId:(NSInteger)companionId
completion:(void(^)(KBChatSessionResetResponse * _Nullable response, NSError * _Nullable error))completion; completion:(void(^)(KBChatSessionResetResponse * _Nullable response, NSError * _Nullable error))completion;
#pragma mark - AI 角色详情接口
/// 根据 ID 获取 AI 角色详情
/// @param companionId AI 角色 ID
/// @param completion 完成回调(返回角色详情)
- (void)fetchCompanionDetailWithCompanionId:(NSInteger)companionId
completion:(void(^)(KBAICompanionDetailModel * _Nullable detail, NSError * _Nullable error))completion;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

View File

@@ -12,6 +12,7 @@
#import "KBLikedCompanionModel.h" #import "KBLikedCompanionModel.h"
#import "KBChattedCompanionModel.h" #import "KBChattedCompanionModel.h"
#import "KBChatSessionResetModel.h" #import "KBChatSessionResetModel.h"
#import "KBAICompanionDetailModel.h"
#import <MJExtension/MJExtension.h> #import <MJExtension/MJExtension.h>
@implementation KBAiSyncData @implementation KBAiSyncData
@@ -753,4 +754,58 @@ autoShowBusinessError:NO
}]; }];
} }
#pragma mark - AI
- (void)fetchCompanionDetailWithCompanionId:(NSInteger)companionId
completion:(void (^)(KBAICompanionDetailModel * _Nullable, NSError * _Nullable))completion {
NSString *path = [NSString stringWithFormat:@"/ai-companion/%ld", (long)companionId];
NSLog(@"[AiVM] %@ request", path);
[[KBNetworkManager shared]
GET:path
parameters:nil
headers:nil
autoShowBusinessError:NO
completion:^(NSDictionary *_Nullable json,
NSURLResponse *_Nullable response,
NSError *_Nullable error) {
if (error) {
NSLog(@"[AiVM] %@ failed: %@", path, error.localizedDescription ?: @"");
if (completion) {
completion(nil, error);
}
return;
}
NSLog(@"[AiVM] %@ response: %@", path, json);
NSInteger code = [json[@"code"] integerValue];
if (code != 0) {
NSString *message = json[@"message"] ?: @"请求失败";
NSError *bizError = [NSError errorWithDomain:@"AiVM"
code:code
userInfo:@{NSLocalizedDescriptionKey: message}];
if (completion) {
completion(nil, bizError);
}
return;
}
id dataObj = json[@"data"];
if ([dataObj isKindOfClass:[NSDictionary class]]) {
KBAICompanionDetailModel *detail = [KBAICompanionDetailModel mj_objectWithKeyValues:dataObj];
if (completion) {
completion(detail, nil);
}
} else {
NSError *parseError = [NSError errorWithDomain:@"AiVM"
code:-1
userInfo:@{NSLocalizedDescriptionKey: @"数据格式错误"}];
if (completion) {
completion(nil, parseError);
}
}
}];
}
@end @end