yangsunyue_wd

desc:评论列表界面

... ... @@ -555,6 +555,12 @@ export class HttpUrlUtils {
return url
}
/*获取子评论列表*/
static getChildContentCommentListDataUrl() {
let url = HttpUrlUtils._hostUrl + "/api/rmrb-comment/comment/zh/c/childCommentList"
return url
}
/*评论状态*/
static getBatchCommentStatusUrl() {
let url = HttpUrlUtils._hostUrl + "/api/rmrb-comment/comment/zh/c/batchCommentStatus"
... ... @@ -567,6 +573,18 @@ export class HttpUrlUtils {
return url
}
/*发布评论*/
static getPublishCommentUrl() {
let url = HttpUrlUtils._hostUrl + "/api/rmrb-comment/comment/zh/c/publish"
return url
}
/*游客发布评论*/
static getNoUserPublishCommentUrl() {
let url = HttpUrlUtils._hostUrl + "/api/rmrb-comment/comment/zh/c/commentLike"
return url
}
/*levleIcon*/
static getBatchUserUrl() {
let url = HttpUrlUtils._hostUrl + "/api/rmrb-user-point/auth/level/zh/c/batchUser"
... ...
import { LazyDataSource } from 'wdKit/Index'
import PageModel from '../../../viewmodel/PageModel'
... ... @@ -11,13 +12,13 @@ export enum WDPublicUserType {
WDPublicUserType_Unkown = 0,
/// 普通用户
WDPublicUserType_NormalUser = 1,
WDPublicUserType_NormalUser = 1,
/// 号主
WDPublicUserType_AccountOwner = 2,
WDPublicUserType_AccountOwner = 2,
/// 矩阵号
WDPublicUserType_Matrix = 3,
WDPublicUserType_Matrix = 3,
/// 运营子账号
WDPublicUserType_OperatingSubAccount = 4,
... ... @@ -27,16 +28,23 @@ export enum WDPublicUserType {
}
@Observed
export class commentListModel extends PageModel{
pageNum: number = 0
pageSize: number = 0
export class commentListModel extends PageModel {
pageNum: number = 1
pageSize: number = 10
totalCount: number = 0
hasNext: number = 0
list: commentItemModel[] = []
// constructor(pageNum:number, pageSize:number, totalCount: number, hasNext: number, list: commentItemModel[]) {
// super()
// this.pageNum = pageNum
// this.pageSize = pageSize
// this.totalCount = totalCount
// this.hasNext = hasNext
// this.list = list
// }
}
@Observed
export class commentItemModel {
authorLike: string = ''
... ... @@ -44,6 +52,7 @@ export class commentItemModel {
checkStatus: string = ''
childCommentNum: string = ''
childComments: commentItemModel[] = []
childCommentsLazyDataSource: LazyDataSource<commentItemModel> = new LazyDataSource()
commentContent: string = ''
commentContentSensitive: string = ''
commentLevel: number = 0
... ... @@ -60,8 +69,7 @@ export class commentItemModel {
fromUserName: string = ''
fromUserType: WDPublicUserType = 0
id: string = ''
likeNum: string = ''
likeNum: string = '0'
mySelf: string = ''
parentId: string = ''
region: string = ''
... ... @@ -77,36 +85,32 @@ export class commentItemModel {
uuid: string = ''
/*本地使用,收起时默认3行 -1为不限制行数*/
maxLine: number = 3
/*是否有展示更多*/
hasMore:boolean = false
hasMore: boolean = false
/*当有展示更多的时候,当前的状态是展开还是收起*/
expanded:boolean = false
highQualityExpireTime:string = '';
highQualityTime:string = '';
targetTitle:string = '';
targetStatus:string = '';
targetId:string = '';
targetRelId:string = '';
targetRelObjectId:string = '';
targetRelType:string = '';
targetType:string = '';
visitorComment:string = '';
shareInfo:commentItemShareInfoModel = new commentItemShareInfoModel;
api_commentId:string = '';
expanded: boolean = false
/*是否正在加载子评论*/
isLoading: boolean = false
highQualityExpireTime: string = '';
highQualityTime: string = '';
targetTitle: string = '';
targetStatus: string = '';
targetId: string = '';
targetRelId: string = '';
targetRelObjectId: string = '';
targetRelType: string = '';
targetType: string = '';
visitorComment: string = '';
shareInfo: commentItemShareInfoModel = new commentItemShareInfoModel;
api_commentId: string = '';
/*评论点赞状态 0-未点赞 1-已点赞*/
api_status:boolean = false;
api_level:string = '';
api_levelHead:string = 'http';
api_userId:string = '';
api_creatorId:string = '';
api_userType:string = '';
api_authIcon:string = '';
api_status: boolean = false;
api_level: string = '';
api_levelHead: string = 'http';
api_userId: string = '';
api_creatorId: string = '';
api_userType: string = '';
api_authIcon: string = '';
}
@Observed
... ... @@ -118,7 +122,7 @@ export class commentItemShareInfoModel {
}
@Observed
export class commentStatusListModel extends PageModel{
export class commentStatusListModel extends PageModel {
pageNum: number = 0
pageSize: number = 0
totalCount: number = 0
... ... @@ -129,18 +133,17 @@ export class commentStatusListModel extends PageModel{
@Observed
export class commentStatusModel {
commentId:string = '';
status:boolean = false;
level:string = '';
levelHead:string = '';
userId:string = '';
commentId: string = '';
status: boolean = false;
level: string = '';
levelHead: string = '';
userId: string = '';
creatorId: string = '';
userType: string = '';
authIcon: string = '';
}
creatorId:string = '';
userType:string = '';
authIcon:string = '';
}
... ...
import { commentItemModel } from './CommentModel';
class BasicDataSource implements IDataSource {
private listeners: DataChangeListener[] = [];
private originDataArray: commentItemModel[] = [];
public totalCount(): number {
return 0;
}
public getData(index: number): commentItemModel {
return this.originDataArray[index];
}
registerDataChangeListener(listener: DataChangeListener): void {
if (this.listeners.indexOf(listener) < 0) {
console.info('add listener');
this.listeners.push(listener);
}
}
unregisterDataChangeListener(listener: DataChangeListener): void {
const pos = this.listeners.indexOf(listener);
if (pos >= 0) {
console.info('remove listener');
this.listeners.splice(pos, 1);
}
}
notifyDataReload(): void {
this.listeners.forEach(listener => {
listener.onDataReloaded();
})
}
notifyDataAdd(index: number): void {
this.listeners.forEach(listener => {
listener.onDataAdd(index);
})
}
notifyDataChange(index: number): void {
this.listeners.forEach(listener => {
listener.onDataChange(index);
})
}
notifyDataDelete(index: number): void {
this.listeners.forEach(listener => {
listener.onDataDelete(index);
})
}
notifyDataMove(from: number, to: number): void {
this.listeners.forEach(listener => {
listener.onDataMove(from, to);
})
}
}
export class MyCommentDataSource extends BasicDataSource {
private dataArray: commentItemModel[] = [];
public totalCount(): number {
return this.dataArray.length;
}
public getData(index: number): commentItemModel {
return this.dataArray[index];
}
public addData(index: number, data: commentItemModel): void {
this.dataArray.splice(index, 0, data);
this.notifyDataAdd(index);
}
public pushData(data: commentItemModel): void {
this.dataArray.push(data);
this.notifyDataAdd(this.dataArray.length - 1);
}
}
\ No newline at end of file
... ...
@Observed
export class publishCommentModel {
/*被评论的内容id*/
targetId: string = ""
/*被评论的内容关系id*/
targetRelId: string = ""
/*1.文字 2.文字+表情 3.定制表情(客户端写死) 4.图片*/
commentType: string = '1'
/*根评论id,如果是一级评论,传-1;否则,传当前评论所属的根评论id*/
rootCommentId: string = "-1"
/*【迭代二新增】内容的标题,取bff内容详情接口中newsTitle字段*/
targetTitle: string = ""
/*被评论的内容关系类型,1.频道关系;2.专题关系;【人民号内容为空】默认0*/
targetRelType: string = ''
/*【迭代二新增】关联的频道id/专题id;*/
targetRelObjectId: string = ""
/*评论图片url,多个逗号隔开*/
commentPics: string = ""
/*评论内容*/
commentContent: string = ""
/*【迭代二新增】是否是重点稿件 1是 0否*/
keyArticle: string = ''
/*内容类别, 1:点播,2:直播,3:活动,4:广告,5:专题,6:链接,7:榜单,8:图文,9:组图,10:H5新闻,11:频道,12:组件,13:音频,14:动态(13和14为中文版新增)*/
targetType: string = ''
/*父评论id,如果是其它评论的回复,该字段必填*/
parentId: string = "-1"
placeHolderText: string = "优质评论会获得最佳评论人的称号"
}
... ...
... ... @@ -6,38 +6,68 @@ import { commentItemModel, commentListModel, WDPublicUserType } from '../model/C
import commentViewModel from '../viewmodel/CommentViewModel'
import { CommentText } from './CommentText';
import measure from '@ohos.measure'
import {CommentCustomDialog} from './CommentCustomDialog'
import { CommentCustomDialog } from './CommentCustomDialog'
import { publishCommentModel } from '../model/PublishCommentModel';
import { ifaa } from '@kit.OnlineAuthenticationKit';
const TAG = 'CommentComponent';
@Entry
// @Entry
@Preview
@Component
export struct CommentComponent {
@State private browSingModel: commentListModel = new commentListModel()
@State contentId: string = '30004266013'
/*内容类别, 1:点播,2:直播,3:活动,4:广告,5:专题,6:链接,7:榜单,8:图文,9:组图,10:H5新闻,11:频道,12:组件,13:音频,14:动态(13和14为中文版新增)*/
@State contentType: string = '8'
/*内容的标题,取bff内容详情接口中newsTitle字段*/
@State targetTitle: string = '北约同意向乌克兰提供防空系统在内的更多军事支持'
/*被评论的内容关系id*/
@State targetRelId: string = "500002849023"
/*关联的频道id/专题id*/
@State targetRelObjectId: string = "2002"
/*是否是重点稿件 1是 0否*/
@State keyArticle: string = "0"
/*被评论的内容关系类型,1.频道关系;2.专题关系;【人民号内容为空】默认0*/
@State targetRelType: string = "1"
// @State private browSingModel: commentListModel = new commentListModel()
isloading: boolean = false
@State allDatas: LazyDataSource<commentItemModel> = new LazyDataSource();
dialogController: CustomDialogController = new CustomDialogController({
builder: CommentCustomDialog(),
@State publishCommentModel: publishCommentModel = new publishCommentModel()
@State dialogController: CustomDialogController | null = new CustomDialogController({
builder: CommentCustomDialog({
confirm: (value: Record<string, string>) => {
this.publishComment(value)
},
commentText: this.publishCommentModel.commentContent,
placeHolderText: this.publishCommentModel.placeHolderText,
}),
autoCancel: true,
alignment: DialogAlignment.Bottom,
customStyle: true,
offset: {
dx: 0,
dy: -20
}
},
})
// 在自定义组件即将析构销毁时将dialogControlle置空
aboutToDisappear() {
this.dialogController = null // 将dialogController置空
}
aboutToAppear() {
this.publishCommentModel.targetTitle = this.targetTitle
this.publishCommentModel.targetId = this.contentId
this.publishCommentModel.targetType = this.contentType
this.publishCommentModel.targetRelId = this.targetRelId
this.publishCommentModel.targetRelType = this.targetRelType
this.publishCommentModel.targetRelObjectId = this.targetRelObjectId
this.publishCommentModel.keyArticle = this.keyArticle
this.getData();
this.getData();
this.getData();
this.getData();
}
/*标题:全部评论*/
... ... @@ -64,109 +94,346 @@ export struct CommentComponent {
/*1级评论作为titleHeader*/
@Builder
CommentHeaderItem(item: commentItemModel) {
CommentHeaderItem(item: commentItemModel, index: number) {
commentHeaderView({
item: item,
dialogController: this.dialogController,
publishCommentModel: this.publishCommentModel
})
}
/*查看更多和收起*/
@Builder
GroupFooterView(item: commentItemModel, index: number) {
footerExpandedView({ item: item, contentId: this.contentId, contentType: this.contentType })
}
build() {
Column() {
List() {
ListItemGroup({ header: this.titleHeader() })
LazyForEach(this.allDatas, (item: commentItemModel, index: number) => {
if (item.hasMore) {
ListItemGroup({ header: this.CommentHeaderItem(item, index), footer: this.GroupFooterView(item, index) }) {
LazyForEach(item.childCommentsLazyDataSource, (childItem: commentItemModel, subIndex: number) => {
ListItem() {
ChildCommentItem({
item: childItem,
dialogController: this.dialogController,
publishCommentModel: this.publishCommentModel
});
}
.onClick(() => {
console.log(TAG)
})
})
}
} else {
ListItemGroup({ header: this.CommentHeaderItem(item, index) }) {
LazyForEach(item.childCommentsLazyDataSource, (childItem: commentItemModel, subIndex: number) => {
ListItem() {
ChildCommentItem({
item: childItem,
dialogController: this.dialogController,
publishCommentModel: this.publishCommentModel
});
}
.onClick(() => {
console.log(TAG)
})
})
}
}
})
}.layoutWeight(1)
}
}
//获取数据
async getData() {
commentViewModel.fetchContentCommentList('1', this.contentId, this.contentType).then(commentListModel => {
if (commentListModel && commentListModel.list && commentListModel.list.length > 0) {
commentListModel.list.forEach(element => {
element.hasMore = Number.parseInt(element.childCommentNum) ? true : false
let newModel = commentViewModel.deepCopyCommentItemModel(element)
newModel.targetId = this.contentId
newModel.targetType = this.contentType
this.allDatas.push(newModel)
});
}
})
}
/*回复评论*/
publishComment(value: Record<string, string>) {
this.publishCommentModel.commentContent = value['commentContent']
this.publishCommentModel.commentType = value['commentType']
commentViewModel.publishComment(this.publishCommentModel).then(() => {
this.publishCommentModel.commentContent = ''
}).catch(() => {
})
}
}
@Component
struct ChildCommentItem {
@Link publishCommentModel: publishCommentModel
@Link dialogController: CustomDialogController | null
@ObjectLink item: commentItemModel
build() {
Column() {
Row() {
//头像
Stack() {
Image(item.fromUserHeader)
Image(this.item.fromUserHeader)
.alt($r('app.media.default_head'))
.width('32')
.height('32')
.width('24')
.height('24')
.objectFit(ImageFit.Cover)
.borderRadius(16)
Image(item.api_levelHead)
.width('48')
.height('48')
Image(this.item.api_levelHead)
.width('36')
.height('36')
.objectFit(ImageFit.Cover)
.borderRadius(24)
}
.width(48)
.height(48)
.margin({ left: 8 })
.margin({ left: 47 })
.alignContent(Alignment.Center)
.onClick(() => {
// TODO 跳转个人详情
})
//昵称
Text(item.fromUserName)
.fontSize(14)
.fontColor($r('app.color.color_222222'))
.fontWeight(FontWeight.Medium)
.margin({ left: 5 })
Text() {
Span(this.item.fromUserName)
if (this.item.toUserName) {
Span(' ')
ImageSpan($r('app.media.comment_reply')).size({ width: 6, height: 9 }).offset({ y: -2.5 })
Span(' ')
Span(this.item.toUserName)
}
}
.maxLines(1)
.layoutWeight(1)
.fontSize(14)
.fontColor($r('app.color.color_222222'))
.fontWeight(FontWeight.Medium)
.margin({ left: 0 , right:0})
/// 暂时不显示 “我” 的标签了
/// 人民号>置顶>作者
//人民号
// if (item.fromUserType === WDPublicUserType.WDPublicUserType_Matrix) {
Image($r('app.media.comment_rmh_tag')).width(20).height(20).margin({ left: 5 });
// }
if (this.item.fromUserType === WDPublicUserType.WDPublicUserType_Matrix) {
Image($r('app.media.comment_rmh_tag')).width(20).height(20).margin({ left: 5 });
}
//置顶
// if (item.topFlag) {
Image($r('app.media.comment_icon_zhiding')).width(30).height(18).margin({ left: 5 });
// }
if (this.item.topFlag) {
Image($r('app.media.comment_icon_zhiding')).width(30).height(18).margin({ left: 5 });
}
//作者
// if (item.contentAuthor === 1) {
Text('作者')
.fontSize(11)
.fontColor('#968562')
.backgroundColor('#F1EFEB')
.textAlign(TextAlign.Center)
.borderRadius(2)
.width(30)
.height(18)
.margin({ left: 5 });
// }
}
if (this.item.contentAuthor === 1) {
Text('作者')
.fontSize(11)
.fontColor('#968562')
.backgroundColor('#F1EFEB')
.textAlign(TextAlign.Center)
.borderRadius(2)
.width(30)
.height(18)
.margin({ left: 5 });
}
}.margin({ left: 0, right: 16 })
// .backgroundColor(Color.Red)
CommentText({
longMessage: item.commentContent,
longMessage: this.item.commentContent,
maxline: 3,
fontSize: 16,
fontSize: 14,
fontWeight: FontWeight.Regular,
marginWidth: (59 + 16)
marginWidth: (95 + 16)
})
.margin({ left: 59, right: 16 })
.margin({ left: 95, right: 16, top: -5 })
.onClick(() => {
this.publishCommentModel.rootCommentId = this.item.rootCommentId
this.publishCommentModel.parentId = this.item.id
this.publishCommentModel.placeHolderText = '回复' + this.item.fromUserName + ':'
if (this.dialogController != null) {
this.dialogController.open()
}
})
this.CommentFooterView(item);
commentFooterView({
item: this.item,
dialogController: this.dialogController,
publishCommentModel: this.publishCommentModel
}).margin({ left: 95, right: 16 })
}.alignItems(HorizontalAlign.Start)
.width('100%')
}
}
/*查看更多和收起*/
@Builder
GroupFooterView(item: commentItemModel) {
@Component
struct footerExpandedView {
@ObjectLink item: commentItemModel
contentId: string = ''
contentType: string = ''
build() {
Row() {
if (item.expanded){
if (this.item.expanded) {
Row() {
Text('收起').fontColor($r('app.color.color_222222')).fontSize(14)
Image($r('app.media.comment_pickUp')).width(12).height(12)
}.margin({ left: 213 })
}else {
.onClick(() => {
this.item.expanded = !this.item.expanded
this.item.childComments = []
this.item.childCommentsLazyDataSource.clear()
})
} else {
Row() {
Text().backgroundColor($r('app.color.color_EDEDED')).width(24).height(1)
Text('查看更多回复').fontColor($r('app.color.color_222222')).fontSize(14).margin({ left: 6 })
Image($r('app.media.comment_unfold')).width(12).height(12)
}.margin({ left: 53 })
.onClick(() => {
if (this.item.isLoading) {
return
}
this.item.isLoading = true
//load child
commentViewModel.fetchChildContentCommentList('1', this.contentId, this.contentType, this.item.id)
.then((commentListModel) => {
this.item.isLoading = false
this.item.expanded = !this.item.expanded
commentListModel.list.forEach(element => {
this.item.childComments.push(element)
let newModel = commentViewModel.deepCopyCommentItemModel(element)
newModel.targetId = this.contentId
newModel.targetType = this.contentType
this.item.childCommentsLazyDataSource.push(newModel)
})
}).catch(() => {
this.item.isLoading = false
})
})
}
}.height(30)
}
}
@Component
struct commentHeaderView {
@Link publishCommentModel: publishCommentModel
@Link dialogController: CustomDialogController | null
@ObjectLink item: commentItemModel
build() {
Column() {
Row() {
//头像
Stack() {
Image(this.item.fromUserHeader)
.alt($r('app.media.default_head'))
.width('32')
.height('32')
.objectFit(ImageFit.Cover)
.borderRadius(16)
Image(this.item.api_levelHead)
.width('48')
.height('48')
.objectFit(ImageFit.Cover)
.borderRadius(24)
}
.width(48)
.height(48)
.margin({ left: 8 })
.alignContent(Alignment.Center)
.onClick(() => {
// TODO 跳转个人详情
})
//昵称
Text(this.item.fromUserName)
.fontSize(14)
.fontColor($r('app.color.color_222222'))
.fontWeight(FontWeight.Medium)
.margin({ left: 5 })
}.height(30)
/// 暂时不显示 “我” 的标签了
/// 人民号>置顶>作者
//人民号
if (this.item.fromUserType === WDPublicUserType.WDPublicUserType_Matrix) {
Image($r('app.media.comment_rmh_tag')).width(20).height(20).margin({ left: 5 });
}
//置顶
if (this.item.topFlag) {
Image($r('app.media.comment_icon_zhiding')).width(30).height(18).margin({ left: 5 });
}
//作者
if (this.item.contentAuthor === 1) {
Text('作者')
.fontSize(11)
.fontColor('#968562')
.backgroundColor('#F1EFEB')
.textAlign(TextAlign.Center)
.borderRadius(2)
.width(30)
.height(18)
.margin({ left: 5 });
}
}
CommentText({
longMessage: this.item.commentContent,
maxline: 3,
fontSize: 16,
fontWeight: FontWeight.Regular,
marginWidth: (59 + 16)
})
.margin({ left: 59, right: 16, top: -5 })
commentFooterView({
item: this.item,
dialogController: this.dialogController,
publishCommentModel: this.publishCommentModel
}).margin({ left: 59, right: 16 })
}.alignItems(HorizontalAlign.Start)
}
}
/*评论内容下面的IP地址时间点赞*/
@Builder
CommentFooterView(item: commentItemModel) {
/*评论内容下面的IP地址时间点赞*/
@Component
struct commentFooterView {
@Link publishCommentModel: publishCommentModel
@Link dialogController: CustomDialogController | null
@ObjectLink item: commentItemModel
build() {
Row() {
Row({ space: 6 }) {
Text(item.region ? (item.region + '网友') : '人民日报客户端网友')
Text(this.item.region ? (this.item.region + '网友') : '人民日报客户端网友')
.fontColor($r('app.color.color_B0B0B0'))
.fontSize(12);
Image($r('app.media.comment_hyphen'))
... ... @@ -175,15 +442,7 @@ export struct CommentComponent {
height: 4
})
//TODO: 时间格式需要本地调整
// / 展现专用,用于获取多久之前
// ///小于1分钟:刚刚
// ///1~60分钟:x分钟前
// ///1小时~1天:x小时前
// ///1天~2天:1天前
// ///2天~:日期隐藏
Text(DateTimeUtils.getCommentTime(Number.parseFloat(item.createTime)))
Text(DateTimeUtils.getCommentTime(DateTimeUtils.getDateTimestamp(this.item.createTime)))
.fontColor($r('app.color.color_B0B0B0'))
.fontSize(12)
... ... @@ -202,98 +461,51 @@ export struct CommentComponent {
}
Row({ space: 6 }) {
Text(item.likeNum)
Text(this.item.likeNum)
.fontColor($r('app.color.color_666666'))
.fontSize(14)
Image($r('app.media.comment_like_normal'))
Image($r(this.item.api_status ? 'app.media.comment_like_select' : 'app.media.comment_like_normal'))
.size({
width: 16,
height: 16
})
.onClick(() => {
//TODO: 点赞
})
}
.onClick(() => {
commentLikeChange(this.item)
commentViewModel.commentLike(this.item).then(() => {
}).catch(() => {
commentLikeChange(this.item)
})
})
}
.justifyContent(FlexAlign.SpaceBetween)
.width('100%')
.height(30)
.margin({ left: 59, right: 16 })
}
}
build() {
Column() {
List() {
ListItemGroup({ header: this.titleHeader() })
.onClick(()=>{
console.log(TAG)
this.dialogController.open()
})
LazyForEach(this.allDatas, (item: commentItemModel, index: number) => {
if (item.hasMore) {
ListItemGroup({ header: this.CommentHeaderItem(item), footer: this.GroupFooterView(item) }) {
ForEach(item.childComments, (childItem: commentItemModel, subIndex: number) => {
ListItem() {
ChildCommentItem();
}
.onClick(()=>{
console.log(TAG)
})
})
}
}else {
ListItemGroup({ header: this.CommentHeaderItem(item)}) {
ForEach(item.childComments, (childItem: commentItemModel, subIndex: number) => {
ListItem() {
ChildCommentItem();
}
.onClick(()=>{
console.log(TAG)
})
})
}
}
})
}.layoutWeight(1)
function commentLikeChange(item: commentItemModel) {
item.api_status = !item.api_status
//点赞
if (item.api_status) {
if (item.likeNum.length > 0) {
item.likeNum = (Number.parseInt(item.likeNum) + 1) + ''
} else {
item.likeNum = '1'
}
}
//获取数据
async getData() {
this.browSingModel.currentPage = 1
commentViewModel.getCommentLocal(getContext()).then(commentListModel => {
if (commentListModel && commentListModel.list && commentListModel.list.length > 0) {
commentListModel.hasMore = true;
this.browSingModel.viewType = ViewType.LOADED;
this.allDatas.push(...commentListModel.list)
if (commentListModel.list.length === this.browSingModel.pageSize) {
this.browSingModel.currentPage++;
this.browSingModel.hasMore = true;
} else {
this.browSingModel.hasMore = false;
}
} else {
this.browSingModel.viewType = ViewType.EMPTY;
}
})
}
/*回复评论*/
ReplyComment() {
//取消点赞
if (!item.api_status) {
item.likeNum = (Number.parseInt(item.likeNum) - 1) + ''
if (Number.parseInt(item.likeNum) <= 0) {
item.likeNum = ''
}
}
}
@Component
struct ChildCommentItem {
build() {
Text('child')
}
}
... ...
import { inputMethodEngine } from '@kit.IMEKit'
import { publishCommentModel } from '../model/PublishCommentModel'
import commentViewModel from '../viewmodel/CommentViewModel'
@Preview
@CustomDialog
export struct CommentCustomDialog {
controller: CustomDialogController = new CustomDialogController({
builder: CommentCustomDialog(),
autoCancel: true,
alignment: DialogAlignment.Bottom,
customStyle: true,
})
commentText: string = ''
placeHolderText: string = '优质评论会获得最佳评论人的称号'
controller?: CustomDialogController
confirm: (value: Record<string, string>) => void = () => {
}
@State private emojiSwitch: boolean = false
textInputController: TextAreaController = new TextAreaController()
build() {
Column() {
Row() {
TextArea({ placeholder: '优质评论会获得最佳评论人的称号' })
TextArea({
placeholder: this.placeHolderText,
controller: this.textInputController,
text: this.commentText
})
.height('100%')
.width('100%')
.backgroundColor($r('app.color.color_transparent'))
.onChange(value => {
this.commentText = value;
})
}
.backgroundColor('#F9F9F9')
// .width('100%')
.margin({ top: 12,right: 12, left: 12, bottom: 10 })
.margin({ top: 12, right: 12, left: 12, bottom: 10 })
.height(80)
.borderRadius(4)
Row(){
Row() {
Row({ space: 12 }) {
//语音暂时不做,隐藏
// Image($r('app.media.WDInput_voice')).width(30).height(30)
Row() {
Row({ space: 12 }) {
//语音暂时不做,隐藏
// Image($r('app.media.WDInput_voice')).width(30).height(30)
Image($r('app.media.WDInput_keyboardImage')).width(30).height(30)
}
// Blank()
Image($r(this.emojiSwitch ? 'app.media.WDInput_keyboardImage' : 'app.media.WDInput_emojiImage'))
.width(30)
.height(30)
.onClick(() => {
// this.commentText = this.commentText + '神鼎'
this.emojiSwitch = !this.emojiSwitch
if (this.emojiSwitch) {
this.textInputController.stopEditing()
} else {
this.textInputController.caretPosition(this.textInputController.getTextContentRect().x)
}
})
}
// Blank()
Row() {
Text('发布')
.backgroundColor('#F89381')
.width(80)
.height(30)
.fontSize(15)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.borderRadius(4)
.onClick(() => {
if (this.commentText.length > 0) {
//请求评论接口
//commentType
//commentContent
let bean: Record<string, string> = {};
bean['commentContent'] = this.commentText
//TODO 判断类型
bean['commentType'] = '1'
this.confirm(bean)
if (this.controller != null) {
this.controller.close()
}
}
})
}
}.justifyContent(FlexAlign.SpaceBetween)
.width('100%')
.height(60)
// .margin({ right: 12, left: 12 })
// .backgroundColor(Color.Red)
}.padding({ left: 12, right: 12 })
//表情view
if (this.emojiSwitch) {
emojiView()
}
Row() {
Text('发布')
.backgroundColor('#F89381')
.width(80)
.height(30)
.fontSize(15)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.borderRadius(4)
}
}.justifyContent(FlexAlign.SpaceBetween)
.width('100%')
.height(60)
// .margin({ right: 12, left: 12 })
// .backgroundColor(Color.Red)
}.padding({left:12, right:12})
}.backgroundColor(Color.White)
.width('100%')
.offset({
... ... @@ -56,6 +105,12 @@ export struct CommentCustomDialog {
}
}
@Component
struct emojiView {
build() {
}
}
... ...
... ... @@ -13,10 +13,9 @@ export struct CommentText {
@State longMessage: string = ''
// 最大显示行数
@State maxLineMesssage: string = '';
@State lines: number = 3;
@State maxline: number = 3;
@State marginWidth:number = 0;
@State marginWidth: number = 0;
// 长文本状态(展开 or 收起)
@State collapseText: string = collapseString
// 屏幕宽度(单位px)
... ... @@ -30,7 +29,6 @@ export struct CommentText {
fontColor: ResourceColor = $r('app.color.color_222222')
// 测量文本宽度(单位px)
@State textWidth: number = 0;
// constructor(longMessage?:string,) {
// super();
// this.longMessage = longMessage;
... ... @@ -38,8 +36,6 @@ export struct CommentText {
// 获取当前所有的display对象
promise: Promise<Array<display.Display>> = display.getAllDisplays()
aboutToAppear() {
console.log(`文本宽度为:${this.textWidth}`)
let padding = vp2px(5 + this.marginWidth)
... ... @@ -48,7 +44,7 @@ export struct CommentText {
textContent: this.longMessage,
fontSize: this.fontSize,
fontWeight: this.fontWeight,
constraintWidth:(this.screenWidth - padding)
constraintWidth: (this.screenWidth - padding)
})
console.log(`文本宽度为:${this.textWidth}`)
... ... @@ -66,7 +62,7 @@ export struct CommentText {
let padding = vp2px(5 + this.marginWidth)
let maxLineTextWidth = (this.screenWidth - padding) * this.maxline;
let maxLineTextWidth = (this.screenWidth - padding) * this.maxline;
for (let index = 0; index < this.longMessage.length; index++) {
const element = this.longMessage.substring(0, index)
... ... @@ -75,7 +71,7 @@ export struct CommentText {
textContent: string,
fontSize: this.fontSize,
fontWeight: this.fontWeight,
constraintWidth:(this.screenWidth - padding)
constraintWidth: (this.screenWidth - padding)
})
//计算有误差20
... ... @@ -101,45 +97,46 @@ export struct CommentText {
Column() {
if (this.isExpanded) {
// Stack({ alignContent: Alignment.BottomEnd }) {
Text(this.longMessage) {
Span(this.expandedStates ? this.longMessage : this.maxLineMesssage)
Span(this.collapseText).onClick(() => {
if (this.collapseText == collapseString) {
this.collapseText = uncollapseString;
this.expandedStates = true;
this.lines = -1; // 使得设置的最大行属性无效
// 展开动画
// animateTo({
// duration: 150,
// curve: curves.springMotion(),
// }, () => {
// this.lines = -1; // 使得设置的最大行属性无效
// })
} else {
this.collapseText = collapseString;
this.expandedStates = false;
this.lines = this.maxline; // 只显示3行
// 收起动画
// animateTo({
// duration: 100,
// curve: Curve.Friction,
// }, () => {
// this.lines = this.maxline; // 只显示3行
// })
}
})
}
.width('100%')
.fontSize(this.fontSize)
.fontWeight(this.fontWeight)
.fontColor(this.fontColor)
.maxLines(this.lines)
// .backgroundColor(Color.Red)
Text(this.longMessage) {
Span(this.expandedStates ? this.longMessage : this.maxLineMesssage)
Span(this.collapseText).onClick(() => {
if (this.collapseText == collapseString) {
this.collapseText = uncollapseString;
this.expandedStates = true;
this.lines = -1; // 使得设置的最大行属性无效
// 展开动画
// animateTo({
// duration: 150,
// curve: curves.springMotion(),
// }, () => {
// this.lines = -1; // 使得设置的最大行属性无效
// })
} else {
this.collapseText = collapseString;
this.expandedStates = false;
this.lines = this.maxline; // 只显示3行
// 收起动画
// animateTo({
// duration: 100,
// curve: Curve.Friction,
// }, () => {
// this.lines = this.maxline; // 只显示3行
// })
}
})
}
.width('100%')
.fontSize(this.fontSize)
.fontWeight(this.fontWeight)
.fontColor(this.fontColor)
.maxLines(this.lines)
// .backgroundColor(Color.Red)
// }
}
else {
Text('我没有展开收起')
Text(this.longMessage)
.width('100%')
.fontSize(this.fontSize)
.fontWeight(this.fontWeight)
... ...
... ... @@ -4,6 +4,9 @@ import { commentItemModel, commentListModel } from '../model/CommentModel'
import commentViewModel from '../viewmodel/CommentViewModel'
import { router, window } from '@kit.ArkUI'
import { CustomTitleUI } from '../../reusable/CustomTitleUI'
import { MyCommentDataSource } from '../model/MyCommentDataSource'
import { HttpUtils } from 'wdNetwork/src/main/ets/utils/HttpUtils'
import { HttpUrlUtils } from 'wdNetwork/Index'
const TAG = 'QualityCommentsComponent';
... ... @@ -15,11 +18,11 @@ export struct QualityCommentsComponent {
firstPositionY: number = 0;
bottomSafeHeight: string = AppStorage.get<number>('bottomSafeHeight') + 'px';
topSafeHeight: number = AppStorage.get<number>('topSafeHeight') as number;
@State private browSingModel: commentListModel = new commentListModel()
// @State private browSingModel: commentListModel = new commentListModel()
isloading: boolean = false
lastWindowColor: string = '#ffffff'
currentWindowColor: string = '#FF4202'
@State allDatas: LazyDataSource<commentItemModel> = new LazyDataSource();
@State allDatas: MyCommentDataSource = new MyCommentDataSource();
aboutToDisappear(): void {
... ... @@ -37,23 +40,11 @@ export struct QualityCommentsComponent {
commentViewModel.fetchQualityCommentList('1').then((commentListModel) => {
if (commentListModel && commentListModel.list && commentListModel.list.length > 0) {
// commentListModel.hasMore = true;
// this.browSingModel.viewType = ViewType.LOADED;
// commentListModel.list.forEach(element => {
// this.allDatas.push(new commentItemModel())
// });
this.allDatas.push(...commentListModel.list)
// if (commentListModel.list.length === this.browSingModel.pageSize) {
// this.browSingModel.currentPage++;
// this.browSingModel.hasMore = true;
// } else {
// this.browSingModel.hasMore = false;
// }
commentListModel.list.forEach(element => {
this.allDatas.pushData(commentViewModel.deepCopyCommentItemModel(element))
});
} else {
this.browSingModel.viewType = ViewType.EMPTY;
}
})
}
... ... @@ -61,13 +52,7 @@ export struct QualityCommentsComponent {
fullScreen() {
const windowStage = WindowModel.shared.getWindowStage() as window.WindowStage
const windowClass: window.Window = windowStage.getMainWindowSync(); // 获取应用主窗口
// windowClass.setWindowBackgroundColor(this.currentWindowColor)
windowClass.setWindowLayoutFullScreen(true)
// windowClass.setWindowSystemBarProperties({ statusBarColor: '#fff' })
// windowClass.setWindowLayoutFullScreen(true).then(() => {
// console.log(TAG + 'setWindowLayoutFullScreen');
// })
}
... ... @@ -174,7 +159,7 @@ export struct QualityCommentsComponent {
// ListItemGroup({ header: this.titleHeader() })
LazyForEach(this.allDatas, (item: commentItemModel, index: number) => {
ListItem() {
QualityCommentItem({ item: item, index:index }).margin({ left: 12, right: 12 })
QualityCommentItem({ item: item, index: index }).margin({ left: 12, right: 12 })
}
})
ListItem() {
... ... @@ -217,7 +202,7 @@ export struct QualityCommentsComponent {
@Component
struct QualityCommentItem {
@ObjectLink item: commentItemModel
index:number = 0
index: number = 0
build() {
Column() {
... ... @@ -227,6 +212,8 @@ struct QualityCommentItem {
RelativeContainer() {
Image(this.item.fromUserHeader)
.alt($r(commentViewModel.adjustUserType(this.item.fromUserType) ? 'app.media.WDAccountOwnerHedaerDefaultIcon' : 'app.media.WDAccountDefaultIcon'))
.width(50)
.height(50)
.borderRadius(25)
... ... @@ -326,13 +313,10 @@ struct QualityCommentItem {
.margin({ left: 3 })
}
}.onClick(() => {
this.item.api_status = !this.item.api_status
// commentViewModel.commnetLikeChange(this.item)
commentViewModel.commnetLikeChange(this.item)
commentViewModel.commentLike(this.item).then(() => {
}).catch(() => {
// commentViewModel.commnetLikeChange(this.item)
commentViewModel.commnetLikeChange(this.item)
})
})
}
... ...
import { Logger, ResourcesUtils, UserDataLocal } from 'wdKit/Index';
import { DateTimeUtils, Logger, ResourcesUtils, ToastUtils, UserDataLocal } from 'wdKit/Index';
import { HttpBizUtil, HttpUrlUtils, ResponseDTO } from 'wdNetwork/Index';
import { HttpRequest } from 'wdNetwork/src/main/ets/http/HttpRequest';
import { commentItemModel, commentListModel, commentStatusListModel, commentStatusModel } from '../model/CommentModel';
import {
commentItemModel,
commentListModel,
commentStatusListModel,
commentStatusModel,
WDPublicUserType
} from '../model/CommentModel';
import HashMap from '@ohos.util.HashMap';
import { ifaa } from '@kit.OnlineAuthenticationKit';
import { publishCommentModel } from '../model/PublishCommentModel';
const TAG = "CommentViewModel"
... ... @@ -21,30 +28,68 @@ class CommentViewModel {
return CommentViewModel.instance;
}
/*获取本地mock数据*/
async getCommentLocal(context: Context): Promise<commentListModel> {
Logger.info(TAG, `getBottomNavDataMock start`);
let compRes: ResponseDTO<commentListModel> | null = await ResourcesUtils.getResourcesJson<ResponseDTO<commentListModel>>(context, 'comment_local.json');
if (!compRes || !compRes.data) {
Logger.info(TAG, `getAppointmentListDataLocal compRes is empty`);
return new commentListModel()
}
Logger.info(TAG, `getAppointmentListDataLocal getResourcesJsonSync compRes : ${JSON.stringify(compRes)}`);
return this.fetchCommentStatusAndConfigAuthIcon(compRes.data)
// this.fetchCommentStatusAndConfigAuthIcon(compRes.data)
// return compRes.data
/*获取所有评论*/
fetchContentCommentList(pageNum: string, contentId: string, contentType: string): Promise<commentListModel> {
let url = HttpUrlUtils.getContentCommentListDataUrl() + `?&pageSize=${10}&pageNum=${pageNum}&contentId=${contentId}&contentType=${contentType}&deviceId=${HttpUrlUtils.getDeviceId()}&userId=${HttpUrlUtils.getUserId()}&userType=${HttpUrlUtils.getUserType()}&time=${DateTimeUtils.getCurTime(DateTimeUtils.PATTERN_DATE_TIME_HYPHEN)}`
url = url.replace(' ', '%20')
let headers: HashMap<string, string> = HttpUrlUtils.getCommonHeaders();
return new Promise<commentListModel>((success, fail) => {
HttpRequest.get<ResponseDTO<commentListModel>>(url, headers).then((data: ResponseDTO<commentListModel>) => {
if (!data || !data.data) {
fail("数据为空")
return
}
if (data.code != 0) {
fail(data.message)
return
}
let listData = data.data as commentListModel
this.fetchCommentStatusAndConfigAuthIcon(listData).then((commentListModel) => {
console.log(TAG, 'fetchCommentStatusAndConfigAuthIcon完成')
success(commentListModel)
})
}, (error: Error) => {
fail(error.message)
Logger.debug(TAG, error.toString())
})
})
}
/*获取热门评论本地mock数据*/
async fetchQualityCommentListLocal(context: Context): Promise<commentListModel> {
Logger.info(TAG, `getBottomNavDataMock start`);
let compRes: ResponseDTO<commentListModel> | null = await ResourcesUtils.getResourcesJson<ResponseDTO<commentListModel>>(context, 'qualityComment_local.json');
if (!compRes || !compRes.data) {
Logger.info(TAG, `getAppointmentListDataLocal compRes is empty`);
return new commentListModel()
}
Logger.info(TAG, `getAppointmentListDataLocal getResourcesJsonSync compRes : ${JSON.stringify(compRes)}`);
return this.fetchCommentStatusAndConfigAuthIcon(compRes.data)
/*获取所有子评论*/
fetchChildContentCommentList(pageNum: string, contentId: string, contentType: string, commentId: String): Promise<commentListModel> {
// https://pd-apis-uat.pdnews.cn/api/rmrb-comment/comment/zh/c/childCommentList?commentId=44846810&contentId=30004266013&contentType=8&deviceId=35C78D13-A84A-47CE-A5D0-E114E4E49939&pageNum=1&pageSize=10&time=2024-04-23%2014%3A44%3A57&userId=&userType=0
let url = HttpUrlUtils.getChildContentCommentListDataUrl() + `?&pageSize=${10}&pageNum=${pageNum}&commentId=${commentId}&contentId=${contentId}&contentType=${contentType}&deviceId=${HttpUrlUtils.getDeviceId()}&userId=${HttpUrlUtils.getUserId()}&userType=${HttpUrlUtils.getUserType()}&time=${DateTimeUtils.getCurTime(DateTimeUtils.PATTERN_DATE_TIME_HYPHEN)}`
url = url.replace(' ', '%20')
let headers: HashMap<string, string> = HttpUrlUtils.getCommonHeaders();
return new Promise<commentListModel>((success, fail) => {
HttpRequest.get<ResponseDTO<commentListModel>>(url, headers).then((data: ResponseDTO<commentListModel>) => {
if (!data || !data.data) {
fail("数据为空")
return
}
if (data.code != 0) {
fail(data.message)
return
}
let listData = data.data as commentListModel
// success(listData)
this.fetchCommentStatusAndConfigAuthIcon(listData).then((commentListModel) => {
console.log(TAG, 'fetchCommentStatusAndConfigAuthIcon完成')
success(commentListModel)
})
}, (error: Error) => {
fail(error.message)
Logger.debug(TAG, error.toString())
})
})
}
/*获取热门评论*/
... ... @@ -75,7 +120,7 @@ class CommentViewModel {
})
}
/*点赞*/
/*评论点赞*/
commentLike(model: commentItemModel) {
return new Promise<void>((success, fail) => {
... ... @@ -116,6 +161,43 @@ class CommentViewModel {
})
}
/*发布评论*/
publishComment(model: publishCommentModel) {
return new Promise<void>((success, fail) => {
let url = HttpUrlUtils.getPublishCommentUrl()
let headers: HashMap<string, string> = HttpUrlUtils.getCommonHeaders();
let bean: Record<string, string> = {};
bean['targetId'] = model.targetId;
bean['targetRelId'] = model.targetRelId;
bean['commentType'] = model.commentType;
bean['rootCommentId'] = model.rootCommentId
bean['targetTitle'] = model.targetTitle
bean['targetRelType'] = model.targetRelType
bean['targetRelObjectId'] = model.targetRelObjectId
bean['commentPics'] = model.commentPics
bean['commentContent'] = model.commentContent
bean['keyArticle'] = model.keyArticle
bean['targetType'] = model.targetType
bean['parentId'] = model.parentId
HttpRequest.post<ResponseDTO<commentStatusModel[]>>(url, bean, headers).then((data: ResponseDTO<commentStatusModel[]>) => {
if (data.code != 0) {
ToastUtils.showToast(data.message, 1000);
fail()
return
}
ToastUtils.showToast(data.message, 1000);
success()
}, (error: Error) => {
ToastUtils.showToast('评论失败', 1000);
fail()
Logger.debug(TAG, error.toString())
})
})
}
/*多接口批查*/
fetchCommentStatusAndConfigAuthIcon(model: commentListModel): Promise<commentListModel> {
... ... @@ -139,7 +221,7 @@ class CommentViewModel {
//子评论
if (element.childComments) {
if (element.childComments.length) {
for (const obj2 of element.childComments) {
if ((obj2.id + '').length > 0) {
commentIDs.push(obj2.id + '')
... ... @@ -179,13 +261,13 @@ class CommentViewModel {
return
}
let listData = data.data as commentStatusModel[]
//点赞
//点赞
for (const element of listData) {
for (const commentModel of model.list) {
if (element.commentId == commentModel.id) {
commentModel.api_status = element.status
}
if (commentModel.childComments) {
if (commentModel.childComments.length) {
for (const childCommentModel of commentModel.childComments) {
if (element.commentId == childCommentModel.id) {
childCommentModel.api_status = element.status
... ... @@ -228,7 +310,7 @@ class CommentViewModel {
if (element.userId == commentModel.fromUserId) {
commentModel.api_levelHead = element.levelHead
}
if (commentModel.childComments) {
if (commentModel.childComments.length) {
for (const childCommentModel of commentModel.childComments) {
if (element.userId == childCommentModel.fromUserId) {
childCommentModel.api_levelHead = element.levelHead
... ... @@ -274,7 +356,7 @@ class CommentViewModel {
if (element.creatorId == commentModel.fromCreatorId) {
commentModel.api_authIcon = element.authIcon
}
if (commentModel.childComments) {
if (commentModel.childComments.length) {
for (const childCommentModel of commentModel.childComments) {
if (element.creatorId == childCommentModel.fromCreatorId) {
childCommentModel.api_authIcon = element.authIcon
... ... @@ -303,8 +385,7 @@ class CommentViewModel {
}
commnetLikeChange(model:commentItemModel){
commnetLikeChange(model: commentItemModel) {
model.api_status = !model.api_status
//点赞
if (model.api_status) {
... ... @@ -317,10 +398,97 @@ class CommentViewModel {
model.likeNum = '0'
}
}
// return model
}
deepCopyCommentItemModel(model: commentItemModel) {
let newModel = new commentItemModel()
newModel.authorLike = model.authorLike
newModel.avatarFrame = model.avatarFrame
newModel.checkStatus = model.checkStatus
newModel.childCommentNum = model.childCommentNum
newModel.childComments = model.childComments
// newModel.childCommentsLazyDataSource = model.childCommentsLazyDataSource
newModel.commentContent = model.commentContent
newModel.commentContentSensitive = model.commentContentSensitive
newModel.commentLevel = model.commentLevel
newModel.commentPics = model.commentPics
newModel.commentSensitive = model.commentSensitive
newModel.commentType = model.commentType
newModel.contentAuthor = model.contentAuthor
newModel.createTime = model.createTime
newModel.creatorFlag = model.creatorFlag
newModel.fromCreatorId = model.fromCreatorId
newModel.fromDeviceId = model.fromDeviceId
newModel.fromUserHeader = model.fromUserHeader
newModel.fromUserId = model.fromUserId
newModel.fromUserName = model.fromUserName
newModel.fromUserType = model.fromUserType
newModel.id = model.id
newModel.likeNum = model.likeNum.toString()
if (Number.parseInt(newModel.likeNum) <= 0) {
newModel.likeNum = ''
}
newModel.mySelf = model.mySelf
newModel.parentId = model.parentId
newModel.region = model.region
newModel.replyNum = model.replyNum
newModel.rootCommentId = model.rootCommentId
newModel.sensitiveExist = model.sensitiveExist
newModel.sensitiveShow = model.sensitiveShow
newModel.toUserContentAuthor = model.toUserContentAuthor
newModel.toUserId = model.toUserId
newModel.toUserName = model.toUserName
// newModel.isLoading = model.isLoading
if (model.toUserType != null) {
newModel.toUserType = model.toUserType.toString()
}
newModel.topFlag = model.topFlag
newModel.uuid = model.uuid
newModel.maxLine = model.maxLine
newModel.hasMore = model.hasMore
newModel.expanded = model.expanded
newModel.highQualityExpireTime = model.highQualityExpireTime
newModel.highQualityTime = model.highQualityTime
newModel.targetTitle = model.targetTitle
newModel.targetStatus = model.targetStatus
newModel.targetId = model.targetId
newModel.targetRelId = model.targetRelId
newModel.targetRelObjectId = model.targetRelObjectId
newModel.targetRelType = model.targetRelType
newModel.targetType = model.targetType
newModel.visitorComment = model.visitorComment
newModel.shareInfo = model.shareInfo
newModel.api_commentId = model.api_commentId
newModel.api_status = model.api_status
newModel.api_level = model.api_level
newModel.api_levelHead = model.api_levelHead
newModel.api_userId = model.api_userId
newModel.api_creatorId = model.api_creatorId
newModel.api_authIcon = model.api_authIcon
newModel.api_userType = model.api_userType
return newModel
}
//判断用户类型显示头像
adjustUserType(userType: WDPublicUserType) {
if (userType != 1 && userType > 0) {
return true
}
return false
}
}
const commentViewModel = CommentViewModel.getInstance();
export default commentViewModel as CommentViewModel
\ No newline at end of file
export default commentViewModel as CommentViewModel
... ...