2026-01-29 15:53:26 +08:00
|
|
|
|
//
|
|
|
|
|
|
// AIPersonInfoVC.m
|
|
|
|
|
|
// keyBoard
|
|
|
|
|
|
//
|
|
|
|
|
|
// Created by Mac on 2026/1/29.
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
#import "AIPersonInfoVC.h"
|
2026-01-29 16:03:21 +08:00
|
|
|
|
#import "AiVM.h"
|
|
|
|
|
|
#import "KBAICompanionDetailModel.h"
|
2026-01-29 15:53:26 +08:00
|
|
|
|
#import <SDWebImage/SDWebImage.h>
|
2026-01-29 16:42:43 +08:00
|
|
|
|
#import "AIReportVC.h"
|
2026-01-29 15:53:26 +08:00
|
|
|
|
|
|
|
|
|
|
@interface AIPersonInfoVC ()
|
|
|
|
|
|
|
|
|
|
|
|
/// 背景图
|
|
|
|
|
|
@property (nonatomic, strong) UIImageView *backgroundImageView;
|
|
|
|
|
|
/// 底部磨砂渐变视图
|
|
|
|
|
|
@property (nonatomic, strong) UIVisualEffectView *blurEffectView;
|
|
|
|
|
|
/// 渐变遮罩层
|
|
|
|
|
|
@property (nonatomic, strong) CAGradientLayer *gradientMaskLayer;
|
|
|
|
|
|
/// 左上角关闭按钮
|
|
|
|
|
|
@property (nonatomic, strong) UIButton *closeButton;
|
|
|
|
|
|
/// 右上角更多按钮
|
|
|
|
|
|
@property (nonatomic, strong) UIButton *moreButton;
|
|
|
|
|
|
/// 举报弹窗视图
|
|
|
|
|
|
@property (nonatomic, strong) UIView *reportPopView;
|
|
|
|
|
|
/// 名称标签
|
|
|
|
|
|
@property (nonatomic, strong) UILabel *nameLabel;
|
|
|
|
|
|
/// 介绍标签
|
|
|
|
|
|
@property (nonatomic, strong) UILabel *introLabel;
|
|
|
|
|
|
/// 底部 Go Chatting 按钮
|
|
|
|
|
|
@property (nonatomic, strong) UIButton *goChatButton;
|
2026-01-29 16:03:21 +08:00
|
|
|
|
/// AiVM 实例
|
|
|
|
|
|
@property (nonatomic, strong) AiVM *aiVM;
|
|
|
|
|
|
/// 详情数据
|
|
|
|
|
|
@property (nonatomic, strong) KBAICompanionDetailModel *detailModel;
|
2026-01-29 15:53:26 +08:00
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
@implementation AIPersonInfoVC
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark - Lifecycle
|
|
|
|
|
|
|
|
|
|
|
|
- (void)viewDidLoad {
|
|
|
|
|
|
[super viewDidLoad];
|
|
|
|
|
|
|
|
|
|
|
|
self.kb_navView.hidden = YES;
|
2026-02-02 15:28:00 +08:00
|
|
|
|
// self.view.backgroundColor = [UIColor blackColor];
|
2026-01-29 16:03:21 +08:00
|
|
|
|
self.aiVM = [[AiVM alloc] init];
|
2026-01-29 15:53:26 +08:00
|
|
|
|
|
|
|
|
|
|
/// 1:控件初始化
|
|
|
|
|
|
[self setupUI];
|
|
|
|
|
|
/// 2:绑定事件
|
|
|
|
|
|
[self bindActions];
|
2026-01-29 16:03:21 +08:00
|
|
|
|
/// 3:加载数据
|
2026-01-29 15:53:26 +08:00
|
|
|
|
[self loadData];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (void)viewDidLayoutSubviews {
|
|
|
|
|
|
[super viewDidLayoutSubviews];
|
|
|
|
|
|
// 更新渐变遮罩 frame
|
|
|
|
|
|
self.gradientMaskLayer.frame = self.blurEffectView.bounds;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark - 1:控件初始化
|
|
|
|
|
|
|
|
|
|
|
|
- (void)setupUI {
|
|
|
|
|
|
// 背景图
|
|
|
|
|
|
[self.view addSubview:self.backgroundImageView];
|
|
|
|
|
|
[self.backgroundImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
|
make.edges.equalTo(self.view);
|
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
|
|
// 底部磨砂渐变
|
|
|
|
|
|
[self.view addSubview:self.blurEffectView];
|
|
|
|
|
|
[self.blurEffectView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
|
make.left.right.bottom.equalTo(self.view);
|
|
|
|
|
|
make.height.mas_equalTo(KB_SCREEN_HEIGHT * 0.75);
|
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
|
|
// 左上角关闭按钮
|
|
|
|
|
|
[self.view addSubview:self.closeButton];
|
|
|
|
|
|
[self.closeButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
|
make.left.equalTo(self.view).offset(16);
|
|
|
|
|
|
make.top.equalTo(self.view).offset(KB_STATUSBAR_HEIGHT + 10);
|
|
|
|
|
|
make.width.height.mas_equalTo(32);
|
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
|
|
// 右上角更多按钮
|
|
|
|
|
|
[self.view addSubview:self.moreButton];
|
|
|
|
|
|
[self.moreButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
|
make.right.equalTo(self.view).offset(-16);
|
|
|
|
|
|
make.centerY.equalTo(self.closeButton);
|
|
|
|
|
|
make.width.height.mas_equalTo(32);
|
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
|
|
// 名称标签
|
|
|
|
|
|
[self.view addSubview:self.nameLabel];
|
|
|
|
|
|
[self.nameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
|
make.left.equalTo(self.view).offset(20);
|
|
|
|
|
|
make.right.equalTo(self.view).offset(-20);
|
|
|
|
|
|
make.centerY.equalTo(self.view).offset(20);
|
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
|
|
// 介绍标签
|
|
|
|
|
|
[self.view addSubview:self.introLabel];
|
|
|
|
|
|
[self.introLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
|
make.left.equalTo(self.view).offset(20);
|
|
|
|
|
|
make.right.equalTo(self.view).offset(-20);
|
|
|
|
|
|
make.top.equalTo(self.nameLabel.mas_bottom).offset(16);
|
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
|
|
// 底部 Go Chatting 按钮
|
|
|
|
|
|
[self.view addSubview:self.goChatButton];
|
|
|
|
|
|
[self.goChatButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
|
make.left.equalTo(self.view).offset(40);
|
|
|
|
|
|
make.right.equalTo(self.view).offset(-40);
|
|
|
|
|
|
make.bottom.equalTo(self.view).offset(-KB_SAFE_BOTTOM - 30);
|
|
|
|
|
|
make.height.mas_equalTo(50);
|
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
|
|
// 举报弹窗(初始隐藏)
|
|
|
|
|
|
[self.view addSubview:self.reportPopView];
|
|
|
|
|
|
self.reportPopView.hidden = YES;
|
|
|
|
|
|
[self.reportPopView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
|
make.right.equalTo(self.moreButton.mas_left).offset(8);
|
|
|
|
|
|
make.top.equalTo(self.moreButton.mas_bottom).offset(4);
|
|
|
|
|
|
make.width.mas_equalTo(100);
|
|
|
|
|
|
make.height.mas_equalTo(40);
|
|
|
|
|
|
}];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark - 2:绑定事件
|
|
|
|
|
|
|
|
|
|
|
|
- (void)bindActions {
|
|
|
|
|
|
// 点击空白处隐藏弹窗
|
|
|
|
|
|
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleBackgroundTap:)];
|
|
|
|
|
|
tap.cancelsTouchesInView = NO;
|
|
|
|
|
|
[self.view addGestureRecognizer:tap];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-29 16:03:21 +08:00
|
|
|
|
#pragma mark - 3:加载数据
|
2026-01-29 15:53:26 +08:00
|
|
|
|
|
|
|
|
|
|
- (void)loadData {
|
2026-01-29 16:03:21 +08:00
|
|
|
|
if (self.companionId <= 0) {
|
|
|
|
|
|
NSLog(@"[AIPersonInfoVC] companionId 无效");
|
|
|
|
|
|
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]
|
2026-01-29 15:53:26 +08:00
|
|
|
|
placeholderImage:KBPlaceholderImage];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 设置名称
|
2026-01-29 16:03:21 +08:00
|
|
|
|
self.nameLabel.text = self.detailModel.name ?: @"";
|
2026-01-29 15:53:26 +08:00
|
|
|
|
|
2026-01-29 16:03:21 +08:00
|
|
|
|
// 设置介绍(优先使用 introText,其次 shortDesc)
|
|
|
|
|
|
NSString *intro = self.detailModel.introText.length > 0 ? self.detailModel.introText : self.detailModel.shortDesc;
|
|
|
|
|
|
self.introLabel.text = intro ?: @"";
|
2026-01-29 15:53:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark - Actions
|
|
|
|
|
|
|
|
|
|
|
|
- (void)closeButtonTapped {
|
|
|
|
|
|
[self.navigationController popViewControllerAnimated:YES];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (void)moreButtonTapped {
|
|
|
|
|
|
self.reportPopView.hidden = !self.reportPopView.hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (void)reportButtonTapped {
|
|
|
|
|
|
self.reportPopView.hidden = YES;
|
|
|
|
|
|
|
2026-01-29 16:42:43 +08:00
|
|
|
|
AIReportVC *vc = [[AIReportVC alloc] init];
|
|
|
|
|
|
vc.personaId = self.companionId;
|
|
|
|
|
|
[self.navigationController pushViewController:vc animated:YES];
|
2026-01-29 15:53:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (void)goChatButtonTapped {
|
|
|
|
|
|
[self.navigationController popViewControllerAnimated:YES];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (void)handleBackgroundTap:(UITapGestureRecognizer *)tap {
|
|
|
|
|
|
CGPoint point = [tap locationInView:self.view];
|
|
|
|
|
|
|
|
|
|
|
|
// 如果点击的不是 moreButton 和 reportPopView 区域,则隐藏弹窗
|
|
|
|
|
|
if (!CGRectContainsPoint(self.moreButton.frame, point) &&
|
|
|
|
|
|
!CGRectContainsPoint(self.reportPopView.frame, point)) {
|
|
|
|
|
|
self.reportPopView.hidden = YES;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark - Lazy Load
|
|
|
|
|
|
|
|
|
|
|
|
- (UIImageView *)backgroundImageView {
|
|
|
|
|
|
if (!_backgroundImageView) {
|
|
|
|
|
|
_backgroundImageView = [[UIImageView alloc] init];
|
|
|
|
|
|
_backgroundImageView.contentMode = UIViewContentModeScaleAspectFill;
|
|
|
|
|
|
_backgroundImageView.clipsToBounds = YES;
|
|
|
|
|
|
}
|
|
|
|
|
|
return _backgroundImageView;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (UIVisualEffectView *)blurEffectView {
|
|
|
|
|
|
if (!_blurEffectView) {
|
|
|
|
|
|
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
|
|
|
|
|
|
_blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
|
|
|
|
|
|
_blurEffectView.layer.mask = self.gradientMaskLayer;
|
|
|
|
|
|
}
|
|
|
|
|
|
return _blurEffectView;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (CAGradientLayer *)gradientMaskLayer {
|
|
|
|
|
|
if (!_gradientMaskLayer) {
|
|
|
|
|
|
_gradientMaskLayer = [CAGradientLayer layer];
|
|
|
|
|
|
// 从上到下:透明 -> 不透明
|
|
|
|
|
|
_gradientMaskLayer.colors = @[
|
|
|
|
|
|
(__bridge id)[UIColor clearColor].CGColor,
|
|
|
|
|
|
(__bridge id)[UIColor whiteColor].CGColor
|
|
|
|
|
|
];
|
|
|
|
|
|
_gradientMaskLayer.startPoint = CGPointMake(0.5, 0);
|
|
|
|
|
|
_gradientMaskLayer.endPoint = CGPointMake(0.5, 0.4);
|
|
|
|
|
|
_gradientMaskLayer.locations = @[@0, @1];
|
|
|
|
|
|
}
|
|
|
|
|
|
return _gradientMaskLayer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (UIButton *)closeButton {
|
|
|
|
|
|
if (!_closeButton) {
|
|
|
|
|
|
_closeButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
2026-02-02 15:28:00 +08:00
|
|
|
|
[_closeButton setImage:[UIImage imageNamed:@"ai_close_icon"] forState:UIControlStateNormal];
|
2026-01-29 15:53:26 +08:00
|
|
|
|
[_closeButton addTarget:self action:@selector(closeButtonTapped) forControlEvents:UIControlEventTouchUpInside];
|
|
|
|
|
|
}
|
|
|
|
|
|
return _closeButton;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (UIButton *)moreButton {
|
|
|
|
|
|
if (!_moreButton) {
|
|
|
|
|
|
_moreButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
2026-01-29 16:03:21 +08:00
|
|
|
|
// 使用三个点的图标
|
|
|
|
|
|
UIImage *moreImage = [UIImage imageNamed:@"ai_more_icon"];
|
|
|
|
|
|
if (moreImage) {
|
|
|
|
|
|
[_moreButton setImage:moreImage forState:UIControlStateNormal];
|
|
|
|
|
|
} else {
|
2026-01-29 15:53:26 +08:00
|
|
|
|
// 如果没有图标,使用文字
|
|
|
|
|
|
[_moreButton setTitle:@"•••" forState:UIControlStateNormal];
|
|
|
|
|
|
[_moreButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
|
|
|
|
|
_moreButton.titleLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightBold];
|
|
|
|
|
|
}
|
|
|
|
|
|
[_moreButton addTarget:self action:@selector(moreButtonTapped) forControlEvents:UIControlEventTouchUpInside];
|
|
|
|
|
|
}
|
|
|
|
|
|
return _moreButton;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (UIView *)reportPopView {
|
|
|
|
|
|
if (!_reportPopView) {
|
|
|
|
|
|
_reportPopView = [[UIView alloc] init];
|
|
|
|
|
|
_reportPopView.backgroundColor = [UIColor colorWithWhite:0.2 alpha:0.9];
|
|
|
|
|
|
_reportPopView.layer.cornerRadius = 8;
|
|
|
|
|
|
_reportPopView.clipsToBounds = YES;
|
|
|
|
|
|
|
|
|
|
|
|
// 举报按钮
|
|
|
|
|
|
UIButton *reportBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
2026-01-29 16:03:21 +08:00
|
|
|
|
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);
|
|
|
|
|
|
}
|
2026-01-29 15:53:26 +08:00
|
|
|
|
[reportBtn setTitle:KBLocalized(@"Report") forState:UIControlStateNormal];
|
|
|
|
|
|
[reportBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
|
|
|
|
|
reportBtn.titleLabel.font = [UIFont systemFontOfSize:14];
|
|
|
|
|
|
reportBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
|
|
|
|
|
|
[reportBtn addTarget:self action:@selector(reportButtonTapped) forControlEvents:UIControlEventTouchUpInside];
|
|
|
|
|
|
|
|
|
|
|
|
[_reportPopView addSubview:reportBtn];
|
|
|
|
|
|
[reportBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
|
make.edges.equalTo(_reportPopView);
|
|
|
|
|
|
}];
|
|
|
|
|
|
}
|
|
|
|
|
|
return _reportPopView;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (UILabel *)nameLabel {
|
|
|
|
|
|
if (!_nameLabel) {
|
|
|
|
|
|
_nameLabel = [[UILabel alloc] init];
|
|
|
|
|
|
_nameLabel.font = [UIFont systemFontOfSize:28 weight:UIFontWeightBold];
|
|
|
|
|
|
_nameLabel.textColor = [UIColor whiteColor];
|
|
|
|
|
|
_nameLabel.textAlignment = NSTextAlignmentLeft;
|
|
|
|
|
|
}
|
|
|
|
|
|
return _nameLabel;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (UILabel *)introLabel {
|
|
|
|
|
|
if (!_introLabel) {
|
|
|
|
|
|
_introLabel = [[UILabel alloc] init];
|
|
|
|
|
|
_introLabel.font = [UIFont systemFontOfSize:14];
|
|
|
|
|
|
_introLabel.textColor = [UIColor colorWithWhite:1.0 alpha:0.8];
|
|
|
|
|
|
_introLabel.textAlignment = NSTextAlignmentLeft;
|
|
|
|
|
|
_introLabel.numberOfLines = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
return _introLabel;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (UIButton *)goChatButton {
|
|
|
|
|
|
if (!_goChatButton) {
|
|
|
|
|
|
_goChatButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
|
|
|
|
|
|
|
|
|
|
|
// 设置背景图(如果有的话)
|
|
|
|
|
|
UIImage *bgImage = [UIImage imageNamed:@"ai_go_chat_bg"];
|
|
|
|
|
|
if (bgImage) {
|
|
|
|
|
|
[_goChatButton setBackgroundImage:bgImage forState:UIControlStateNormal];
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 没有背景图时使用渐变色
|
|
|
|
|
|
_goChatButton.backgroundColor = [UIColor colorWithRed:0.8 green:1.0 blue:0.6 alpha:1.0];
|
|
|
|
|
|
_goChatButton.layer.cornerRadius = 25;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[_goChatButton setTitle:KBLocalized(@"Go Chatting") forState:UIControlStateNormal];
|
|
|
|
|
|
[_goChatButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
|
|
|
|
|
|
_goChatButton.titleLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightSemibold];
|
|
|
|
|
|
[_goChatButton addTarget:self action:@selector(goChatButtonTapped) forControlEvents:UIControlEventTouchUpInside];
|
|
|
|
|
|
}
|
|
|
|
|
|
return _goChatButton;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@end
|