// // JXCommentViewController.m // AICity // // Created by TogetherWatch on 2025-10-20. // #import "JXCommentViewController.h" #import "JXAPIService.h" #import "JXCommentContent.h" #import "CommentItemCell.h" #import "CommentRpItemCell.h" #import "CommentFooterView.h" // Cell复用标识符 static NSString * const kCommentCellIdentifier = @"JXCommentCell"; @interface JXCommentViewController () #pragma mark - UI组件 @property (nonatomic, strong) UIView *headerView; @property (nonatomic, strong) UILabel *titleLabel; @property (nonatomic, strong) UIButton *closeButton; @property (nonatomic, strong) UITableView *tableView; @property (nonatomic, strong) UIRefreshControl *refreshControl; @property (nonatomic, strong) UIView *inputContainerView; @property (nonatomic, strong) UITextField *inputTextField; @property (nonatomic, strong) UIButton *submitButton; #pragma mark - 数据 @property (nonatomic, copy) NSString *dramaId; @property (nonatomic, strong) NSMutableArray *commentList; @property (nonatomic, assign) NSInteger currentPage; @property (nonatomic, assign) BOOL isLoading; @property (nonatomic, assign) BOOL hasMoreData; @property (strong, nonatomic) UIView *emptyView; // 回复相关 @property (nonatomic, assign) long long replyToCommentId; @property (nonatomic, copy) NSString *replyToUserName; @end @implementation JXCommentViewController #pragma mark - 初始化 - (instancetype)initWithDramaId:(NSString *)dramaId { self = [super init]; if (self) { _dramaId = dramaId; _currentPage = 1; _hasMoreData = YES; _commentList = [NSMutableArray array]; _replyToCommentId = 0; } return self; } #pragma mark - 生命周期 - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; [self setupUI]; [self loadComments]; // 监听键盘 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } #pragma mark - UI设置 - (void)setupUI { // 顶部标题栏 [self setupHeader]; // 评论列表 [self setupTableView]; // 底部输入框 [self setupInputContainer]; } - (void)setupHeader { self.headerView = [[UIView alloc] init]; self.headerView.backgroundColor = [UIColor whiteColor]; [self.view addSubview:self.headerView]; // 标题 self.titleLabel = [[UILabel alloc] init]; self.titleLabel.text = @"全部评论"; self.titleLabel.font = [UIFont boldSystemFontOfSize:15]; self.titleLabel.textColor = [UIColor colorWithRed:1/255.0 green:1/255.0 blue:1/255.0 alpha:1]; [self.headerView addSubview:self.titleLabel]; // 关闭按钮 self.closeButton = [UIButton buttonWithType:UIButtonTypeSystem]; [self.closeButton setImage:[UIImage imageNamed:@"关闭-1"] forState:UIControlStateNormal]; self.closeButton.tintColor = [UIColor grayColor]; [self.closeButton addTarget:self action:@selector(handleClose) forControlEvents:UIControlEventTouchUpInside]; [self.headerView addSubview:self.closeButton]; // 约束 self.headerView.translatesAutoresizingMaskIntoConstraints = NO; self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO; self.closeButton.translatesAutoresizingMaskIntoConstraints = NO; [NSLayoutConstraint activateConstraints:@[ [self.headerView.topAnchor constraintEqualToAnchor:self.view.topAnchor], [self.headerView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], [self.headerView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], [self.headerView.heightAnchor constraintEqualToConstant:50], [self.titleLabel.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor], [self.titleLabel.leadingAnchor constraintEqualToAnchor:self.headerView.leadingAnchor constant:16], [self.titleLabel.heightAnchor constraintEqualToConstant:50], [self.titleLabel.widthAnchor constraintEqualToConstant:200], [self.closeButton.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor constant:-8], [self.closeButton.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor], [self.closeButton.widthAnchor constraintEqualToConstant:50], [self.closeButton.heightAnchor constraintEqualToConstant:50] ]]; } - (void)setupTableView { self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain]; self.tableView.delegate = self; self.tableView.dataSource = self; self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; self.tableView.backgroundColor = [UIColor whiteColor]; [self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass(CommentItemCell.class) bundle:nil] forCellReuseIdentifier:NSStringFromClass(CommentItemCell.class)]; [self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass(CommentRpItemCell.class) bundle:nil] forCellReuseIdentifier:NSStringFromClass(CommentRpItemCell.class)]; [self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass(CommentFooterView.class) bundle:nil] forHeaderFooterViewReuseIdentifier:NSStringFromClass(CommentFooterView.class)]; [self.view addSubview:self.tableView]; // 下拉刷新 self.refreshControl = [[UIRefreshControl alloc] init]; [self.refreshControl addTarget:self action:@selector(handleRefresh) forControlEvents:UIControlEventValueChanged]; [self.tableView addSubview:self.refreshControl]; // 约束 self.tableView.translatesAutoresizingMaskIntoConstraints = NO; [NSLayoutConstraint activateConstraints:@[ [self.tableView.topAnchor constraintEqualToAnchor:self.headerView.bottomAnchor], [self.tableView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], [self.tableView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], [self.tableView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:-70] ]]; } - (void)setupInputContainer { self.inputContainerView = [[UIView alloc] init]; self.inputContainerView.backgroundColor = UIColor.whiteColor; [self.view addSubview:self.inputContainerView]; // 输入框 self.inputTextField = [[UITextField alloc] init]; self.inputTextField.placeholder = @"说点什么..."; self.inputTextField.backgroundColor = RGBACOLOR(241, 242, 244, 1); self.inputTextField.layer.cornerRadius = 20; self.inputTextField.returnKeyType = UIReturnKeySend; self.inputTextField.leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 12, 0)]; self.inputTextField.leftViewMode = UITextFieldViewModeAlways; self.inputTextField.delegate = self; [self.inputTextField addTarget:self action:@selector(textFieldDidChange) forControlEvents:UIControlEventEditingChanged]; [self.inputContainerView addSubview:self.inputTextField]; self.submitButton = [UIButton buttonWithType:UIButtonTypeCustom]; [self.submitButton setTitle:@"发送" forState:UIControlStateNormal]; [self.submitButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; [self.submitButton setTitleColor:[UIColor whiteColor] forState:UIControlStateDisabled]; self.submitButton.backgroundColor = [UIColor lightGrayColor]; self.submitButton.layer.cornerRadius = 20; self.submitButton.enabled = NO; [self.submitButton addTarget:self action:@selector(handleSubmit) forControlEvents:UIControlEventTouchUpInside]; [self.inputContainerView addSubview:self.submitButton]; // 约束 self.inputContainerView.translatesAutoresizingMaskIntoConstraints = NO; self.inputTextField.translatesAutoresizingMaskIntoConstraints = NO; self.submitButton.translatesAutoresizingMaskIntoConstraints = NO; [NSLayoutConstraint activateConstraints:@[ [self.inputContainerView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], [self.inputContainerView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], [self.inputContainerView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:-safebottom], [self.inputContainerView.heightAnchor constraintEqualToConstant:50], [self.inputTextField.leadingAnchor constraintEqualToAnchor:self.inputContainerView.leadingAnchor constant:16], [self.inputTextField.rightAnchor constraintEqualToAnchor:self.inputContainerView.rightAnchor constant:-86], [self.inputTextField.centerYAnchor constraintEqualToAnchor:self.inputContainerView.centerYAnchor], [self.inputTextField.heightAnchor constraintEqualToConstant:40], // [self.submitButton.leadingAnchor constraintEqualToAnchor:self.inputTextField.trailingAnchor constant:8], [self.submitButton.trailingAnchor constraintEqualToAnchor:self.inputContainerView.trailingAnchor constant:-16], [self.submitButton.centerYAnchor constraintEqualToAnchor:self.inputContainerView.centerYAnchor], [self.submitButton.widthAnchor constraintEqualToConstant:60], [self.submitButton.heightAnchor constraintEqualToConstant:40] ]]; } #pragma mark - 数据加载 - (void)loadComments { if (self.isLoading) { return; } self.isLoading = YES; [[JXAPIService sharedService] getCommentsWithDramaId:self.dramaId page:self.currentPage pageSize:20 success:^(id response) { self.isLoading = NO; [self.refreshControl endRefreshing]; NSDictionary *data = response[@"data"]; NSArray *list = data[@"list"]; // long long totalCount = [data[@"total"] longLongValue]; // 更新标题 self.titleLabel.text = [NSString stringWithFormat:@"全部评论"]; if (list.count == 0) { self.hasMoreData = NO; return; } // 转换为模型 NSMutableArray *models = [NSMutableArray array]; for (NSDictionary *dict in list) { JXCommentContent *comment = [[JXCommentContent alloc] initWithDictionary:dict]; [models addObject:comment]; } if (self.currentPage == 1) { self.commentList = models; } else { [self.commentList addObjectsFromArray:models]; } self.emptyView.hidden = NO; [self.tableView reloadData]; } failure:^(NSError *error) { self.isLoading = NO; [self.refreshControl endRefreshing]; NSLog(@"[JXComment] 加载评论失败: %@", error.localizedDescription); }]; } - (void)handleRefresh { self.currentPage = 1; self.hasMoreData = YES; [self loadComments]; } - (void)loadMoreComments { if (!self.hasMoreData || self.isLoading) { return; } self.currentPage++; [self loadComments]; } #pragma mark - UITableViewDataSource - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ return self.commentList.count; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { JXCommentContent *comment = self.commentList[section]; return comment.isOpen ? comment.reply_count + 1 : 1; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.row == 0) { CommentItemCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass(CommentItemCell.class) forIndexPath:indexPath]; cell.selectionStyle = UITableViewCellSelectionStyleNone; JXCommentContent *comment = self.commentList[indexPath.section]; cell.labelT.text = comment.userName.length ? comment.userName : @"用户001"; cell.labelC.text = comment.content; cell.labelL.text = [NSString stringWithFormat:@"%lld",comment.likeCount]; if (comment.isLiked) { cell.imgL.image = [UIImage imageNamed:@"icon-2.2(1)"]; }else{ cell.imgL.image = [UIImage imageNamed:@"icon-2.2 1"]; } cell.likeClicked = ^{ [self handleLikeComment:comment]; }; cell.huifuClicked = ^{ [self handleReplyComment:comment]; }; return cell; } CommentRpItemCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass(CommentRpItemCell.class) forIndexPath:indexPath]; cell.selectionStyle = UITableViewCellSelectionStyleNone; // JXCommentContent *comment = self.commentList[indexPath.row]; // // // 临时简单展示(后续可创建自定义Cell) // cell.textLabel.numberOfLines = 0; // NSString *likeText = comment.isLiked ? @"❤️" : @"🤍"; // cell.textLabel.text = [NSString stringWithFormat:@"%@ · %@\n%@\n%@ %lld 💬 %lld", // comment.userName, // [comment formattedTime], // comment.content, // likeText, // comment.likeCount, // comment.replyCount]; return cell; } - (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section{ CommentFooterView *header = [tableView dequeueReusableHeaderFooterViewWithIdentifier:NSStringFromClass(CommentFooterView.class)]; JXCommentContent *comment = self.commentList[section]; header.btnOpen.selected = comment.isOpen; header.btnClicked = ^{ comment.isOpen = !comment.isOpen; [self.tableView reloadData]; }; return header; } #pragma mark - UITableViewDelegate - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{ JXCommentContent *comment = self.commentList[section]; return comment.reply_count > 0 ? 0 : 40; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return UITableViewAutomaticDimension; } - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath { return 80; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // [tableView deselectRowAtIndexPath:indexPath animated:YES]; return; if (indexPath.row == 0) { JXCommentContent *comment = self.commentList[indexPath.row]; // 显示操作菜单(点赞、回复) UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet]; // 点赞 NSString *likeTitle = comment.isLiked ? @"取消点赞" : @"点赞"; [alert addAction:[UIAlertAction actionWithTitle:likeTitle style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { [self handleLikeComment:comment]; }]]; // 回复 [alert addAction:[UIAlertAction actionWithTitle:@"回复" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { [self handleReplyComment:comment]; }]]; [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]]; [self presentViewController:alert animated:YES completion:nil]; } } - (void)scrollViewDidScroll:(UIScrollView *)scrollView { // 预加载 CGFloat offsetY = scrollView.contentOffset.y; CGFloat contentHeight = scrollView.contentSize.height; CGFloat scrollViewHeight = scrollView.bounds.size.height; if (offsetY + scrollViewHeight >= contentHeight - 200) { // [self loadMoreComments]; } } #pragma mark - 评论交互 - (void)handleLikeComment:(JXCommentContent *)comment { [[JXAPIService sharedService] likeCommentWithCommentId:comment.commentId success:^(id response) { // 更新UI BOOL isLiked = [response[@"data"][@"isLiked"] boolValue]; long long likeCount = [response[@"data"][@"likeCount"] longLongValue]; comment.isLiked = isLiked; comment.likeCount = likeCount; [self.tableView reloadData]; } failure:^(NSError *error) { NSLog(@"[JXComment] 点赞评论失败: %@", error.localizedDescription); }]; } - (void)handleReplyComment:(JXCommentContent *)comment { self.replyToCommentId = comment.commentId; self.replyToUserName = comment.userName; self.inputTextField.placeholder = [NSString stringWithFormat:@"回复 @%@:", comment.userName]; [self.inputTextField becomeFirstResponder]; } - (void)textFieldDidChange { NSString *text = self.inputTextField.text; self.submitButton.enabled = (text.length > 0); } - (BOOL)textFieldShouldReturn:(UITextField *)textField{ if (textField.text.length == 0) { [MBProgressHUD showMessage:@"请输入评论"]; return NO; } [self handleSubmit]; return YES; } - (void)handleSubmit { NSString *content = self.inputTextField.text; if (content.length == 0) { return; } if (self.replyToCommentId > 0) { // 回复评论 [[JXAPIService sharedService] replyCommentWithCommentId:self.replyToCommentId content:content success:^(id response) { NSLog(@"[JXComment] 回复成功"); [self resetInput]; [self handleRefresh]; } failure:^(NSError *error) { NSLog(@"[JXComment] 回复失败: %@", error.localizedDescription); }]; } else { // 提交新评论 [[JXAPIService sharedService] submitCommentWithDramaId:self.dramaId content:content success:^(id response) { NSLog(@"[JXComment] 评论提交成功"); [self resetInput]; [self handleRefresh]; } failure:^(NSError *error) { NSLog(@"[JXComment] 评论提交失败: %@", error.localizedDescription); }]; } } - (void)resetInput { self.inputTextField.text = @""; self.inputTextField.placeholder = @"说点什么..."; self.submitButton.enabled = NO; self.replyToCommentId = 0; self.replyToUserName = nil; [self.inputTextField resignFirstResponder]; } #pragma mark - 键盘处理 - (void)keyboardWillShow:(NSNotification *)notification { NSDictionary *userInfo = notification.userInfo; CGRect keyboardFrame = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; CGFloat keyboardHeight = keyboardFrame.size.height; [UIView animateWithDuration:0.3 animations:^{ self.inputContainerView.transform = CGAffineTransformMakeTranslation(0, -keyboardHeight); self.tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardHeight, 0); }]; } - (void)keyboardWillHide:(NSNotification *)notification { [UIView animateWithDuration:0.3 animations:^{ self.inputContainerView.transform = CGAffineTransformIdentity; self.tableView.contentInset = UIEdgeInsetsZero; }]; } #pragma mark - 关闭 - (void)handleClose { [self dismissViewControllerAnimated:YES completion:nil]; } @end