| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451 |
- //
- // 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"
- // Cell复用标识符
- static NSString * const kCommentCellIdentifier = @"JXCommentCell";
- @interface JXCommentViewController () <UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate>
- #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<JXCommentContent *> *commentList;
- @property (nonatomic, assign) NSInteger currentPage;
- @property (nonatomic, assign) BOOL isLoading;
- @property (nonatomic, assign) BOOL hasMoreData;
- // 回复相关
- @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.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.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.inputContainerView.translatesAutoresizingMaskIntoConstraints = NO;
- self.inputTextField.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:-16],
- [self.inputTextField.centerYAnchor constraintEqualToAnchor:self.inputContainerView.centerYAnchor],
- [self.inputTextField.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.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 5;
- }
- - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
- // return self.commentList.count;
- return 3;
- }
- - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
- if (indexPath.row == 0) {
- CommentItemCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass(CommentItemCell.class) forIndexPath:indexPath];
- cell.selectionStyle = UITableViewCellSelectionStyleNone;
- 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;
- }
- #pragma mark - UITableViewDelegate
- - (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);
- }
- - (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
|