// Author: fruit.com.cn import 'json_numbers.dart'; /// 评论游标分页大小,契约 §1.7 使用游标而非页码。 const int commentPageSize = 20; /// 评论列表页。 class CommentPage { const CommentPage({ this.comments = const [], this.nextCursor, this.hasMore = false, }); final List comments; final String? nextCursor; final bool hasMore; /// 解析后端 `CursorResult{list,nextCursor,hasMore}`。 factory CommentPage.fromJson(Map json) { final rawList = json['list']; return CommentPage( comments: [ if (rawList is List) for (final item in rawList) if (item is Map) DramaComment.fromJson(item), ], nextCursor: json['nextCursor'] == null ? null : jsonToId(json['nextCursor']), hasMore: json['hasMore'] == true, ); } } /// 服务端评论视图,字段对应 `CommentRespVO`。 class DramaComment { const DramaComment({ required this.id, required this.dramaId, required this.episodeId, required this.parentId, required this.rootId, required this.userId, required this.uid, required this.nickname, required this.avatarUrl, required this.content, required this.status, required this.auditReason, required this.likeCount, required this.replyCount, required this.reportCount, required this.createdAt, required this.mine, required this.liked, }); final String id; final String dramaId; final String episodeId; final String parentId; final String rootId; final String userId; final String uid; final String nickname; final String avatarUrl; final String content; final String status; final String auditReason; final int likeCount; final int replyCount; final int reportCount; final DateTime? createdAt; final bool mine; final bool liked; /// 待人工审核的评论仅本人可见。 bool get isPending => status == 'pending'; /// 顶层评论没有父评论。 bool get isTopLevel => parentId.isEmpty || parentId == '0'; /// 解析 `CommentRespVO`,所有 ID 字段只走字符串解析。 factory DramaComment.fromJson(Map json) => DramaComment( id: jsonToId(json['id']), dramaId: jsonToId(json['dramaId']), episodeId: jsonToId(json['episodeId'], fallback: '0'), parentId: jsonToId(json['parentId'], fallback: '0'), rootId: jsonToId(json['rootId'], fallback: '0'), userId: jsonToId(json['userId']), uid: json['uid']?.toString() ?? '', nickname: json['nickname']?.toString() ?? '', avatarUrl: json['avatarUrl']?.toString() ?? '', content: json['content']?.toString() ?? '', status: json['status']?.toString() ?? '', auditReason: json['auditReason']?.toString() ?? '', likeCount: jsonToInt(json['likeCount']), replyCount: jsonToInt(json['replyCount']), reportCount: jsonToInt(json['reportCount']), createdAt: DateTime.tryParse(json['createdAt']?.toString() ?? ''), mine: json['mine'] == true, liked: json['liked'] == true, ); /// 局部更新点赞或回复数,列表中的其他字段保持不变。 DramaComment copyWith({ int? likeCount, int? replyCount, bool? liked, }) => DramaComment( id: id, dramaId: dramaId, episodeId: episodeId, parentId: parentId, rootId: rootId, userId: userId, uid: uid, nickname: nickname, avatarUrl: avatarUrl, content: content, status: status, auditReason: auditReason, likeCount: likeCount ?? this.likeCount, replyCount: replyCount ?? this.replyCount, reportCount: reportCount, createdAt: createdAt, mine: mine, liked: liked ?? this.liked, ); }