forked from Gitlink/forgeplus-react
379 lines
14 KiB
JavaScript
379 lines
14 KiB
JavaScript
import React, { Component } from 'react';
|
||
import { getImageUrl } from 'educoder';
|
||
import CommentItemMDEditor from './comment-item-editor';
|
||
|
||
import './Comment.css'
|
||
import Modals from '../modals/Modals'
|
||
import { InputNumber, Pagination, Tooltip, Modal } from 'antd'
|
||
import RenderHtml from '../../components/render-html';
|
||
const _origin = window.location.origin;
|
||
|
||
|
||
/*
|
||
tpi讨论、交流问答帖子详情讨论、课堂讨论的公用模块:
|
||
https://www.educoder.net/tasks/n2ejvaowk6l9
|
||
https://www.educoder.net/forums/2629
|
||
注意不同模块使用时的参数的不同 usingAntdModal onlySuperAdminCouldHide isChildCommentPagination等等
|
||
|
||
用到的props:
|
||
user user_url image_url
|
||
|
||
loadingComments--
|
||
comment_count_without_reply
|
||
currentPage
|
||
comments
|
||
|
||
buttonText 发送按钮 显示文本
|
||
|
||
showRewardButton 是否显示奖励按钮
|
||
showHiddenButton 是否显示隐藏按钮
|
||
|
||
onlySuperAdminCouldHide 只有超级管理员才显示隐藏、取消隐藏
|
||
isChildCommentPagination 是否子回复分页
|
||
loadMoreChildComments function 加载所有子回复
|
||
|
||
usingAntdModal 是否使用antd的弹框
|
||
|
||
接口
|
||
deleteComment 删除
|
||
onPaginationChange 翻页变化
|
||
commentPraise 点赞
|
||
hiddenComment 隐藏
|
||
rewardCode 奖励
|
||
|
||
*/
|
||
class Comments extends Component {
|
||
constructor(props) {
|
||
super(props)
|
||
this.handleDialogClose = this.handleDialogClose.bind(this)
|
||
this.handleGoldRewardDialogClose = this.handleGoldRewardDialogClose.bind(this)
|
||
|
||
this.state = {
|
||
dialogOpen: false,
|
||
goldRewardDialogOpen: false,
|
||
goldRewardInput: '',
|
||
|
||
showReplyEditorFlag: false,
|
||
currentReplyComment: null
|
||
}
|
||
}
|
||
initReply(comment) {
|
||
this.props.initReply && this.props.initReply(comment)
|
||
this.setState({
|
||
currentReplyComment: comment,
|
||
showReplyEditorFlag: !this.state.showReplyEditorFlag
|
||
})
|
||
}
|
||
renderChildenComments(comment) {
|
||
if (!comment.children || comment.children.length === 0) {
|
||
return ''
|
||
}
|
||
const { user } = this.props;
|
||
let childCommentsElement = comment.children.map((item, index) => {
|
||
return (
|
||
<div key={index} className="childComment" >
|
||
<div className="J_Comment_Info clearfix mt3">
|
||
<div className="t_info fl">
|
||
<a href={`${_origin}/users/${item.user_login}`} className="content-username hide fl">
|
||
{item.username}
|
||
</a>
|
||
<span className="t_area fl">{item.time}</span>
|
||
{
|
||
item.reward ?
|
||
<Tooltip title={`已奖励金币${item.reward}`} disableFocusListener={true}>
|
||
<a style={{ marginLeft: '20px', cursor: 'default' }}
|
||
className={`rewarded color-grey-8 font-12 fl ${item.admin === true ? '' : 'normalUser'}`}
|
||
>
|
||
<i className="iconfont icon-gift mr5 color-orange fl" style={{ display: 'inline' }}></i><span className="fl">{item.reward}</span>
|
||
</a>
|
||
</Tooltip> : ''
|
||
}
|
||
</div>
|
||
|
||
<p className="fr orig_reply lineh-20">
|
||
<span id="hidden_discuss_btn_952">
|
||
</span>
|
||
{this.props.showRewardButton != false && comment.admin === true ?
|
||
<a className="color-grey-8" onClick={() => this.showGoldRewardDialog(comment, item)}>
|
||
<Tooltip title={"给TA奖励金币"} disableFocusListener={true}>
|
||
<i className="iconfont icon-jiangli fl"></i>
|
||
</Tooltip>
|
||
</a>
|
||
: ""}
|
||
|
||
{/*子回复还没hidden字段*/}
|
||
{false && comment.admin === true ?
|
||
<Tooltip title={item.hidden ? "取消隐藏" : "隐藏评论"}>
|
||
<a className="color-grey-8" onClick={() => this.onCommentBtnClick(comment, item, item.hidden ? 'hiddenCancel' : 'hidden')}>
|
||
<i className={`fa ${item.hidden ? 'fa-eye' : 'fa-eye-slash'} mr5`}></i>
|
||
</a>
|
||
</Tooltip>
|
||
: ""}
|
||
|
||
{/* 新版user_id不准,获取方式不对 */}
|
||
{comment.admin === true || item.can_delete || item.user_id === user.user_id || item.user_login == user.login ?
|
||
<a className="color-grey-8" id="delete_reply_118_952" onClick={() => this.onCommentBtnClick(comment, item, 'delete')}>
|
||
<Tooltip title={"删除"} disableFocusListener={true}>
|
||
<i className="iconfont icon-shanchu mr5"></i>
|
||
</Tooltip>
|
||
</a>
|
||
: null}
|
||
|
||
</p>
|
||
</div>
|
||
|
||
<div className="comment_content clearfix" id={`reply_content_${item.id}`}>
|
||
<div className="color-grey-3" id={`reply_content_${item.id}`}>
|
||
<RenderHtml className="break_word_comments" value={item.content} />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
)
|
||
})
|
||
return childCommentsElement
|
||
}
|
||
renderComments() {
|
||
let { comments, commentPraise, tabIndexChange, user, replyComment } = this.props;
|
||
const { showReplyEditorFlag, currentReplyComment } = this.state;
|
||
if (!comments || comments.length === 0) {
|
||
return;
|
||
}
|
||
// "https://www.educoder.net/users/m02945638"
|
||
let commentsElement = comments.map((item, index) => {
|
||
|
||
return (
|
||
<div className="comment_item_cont df clearfix" key={index}>
|
||
<div className="J_Comment_Face fl">
|
||
<a href={`${_origin}/users/${item.user_login}`} target="_blank">
|
||
<img alt="用户头像" height="50" src={getImageUrl(`images/${item.image_url}`)} width="50" />
|
||
</a>
|
||
</div>
|
||
|
||
<div className="t_content fl">
|
||
<div className="J_Comment_Reply">
|
||
<div className="comment_orig_content" style={{ margin: "0px" }}>
|
||
<div className="J_Comment_Info clearfix mt3">
|
||
<div className="t_info fl">
|
||
<a href={`${_origin}/users/${item.user_login}`} className="content-username hide fl">
|
||
{item.username}
|
||
</a>
|
||
<span className="t_area fl">{item.time}</span>
|
||
{item.position && <span className="fl color-light-green font-14 ml15">[第{item.position}关]</span>}
|
||
{item.game_url ?
|
||
<Tooltip title={`点击查看TA的代码页面`} disableFocusListener={true}>
|
||
<a href={item.game_url} target="_blank" className="fl font-14 ml15"
|
||
style={{ color: "#4CACFF", cursor: "pointer" }}
|
||
>查看</a>
|
||
</Tooltip> : ""}
|
||
|
||
{
|
||
item.reward ?
|
||
<Tooltip title={`已奖励金币${item.reward}`} disableFocusListener={true}>
|
||
<a style={{ marginLeft: '20px', cursor: 'default' }}
|
||
className={`rewarded color-grey-8 font-12 fl ${item.admin === true ? '' : 'normalUser'}`}
|
||
>
|
||
<i className="iconfont icon-gift mr5 color-orange fl"></i><span className="fl">{item.reward}</span>
|
||
</a>
|
||
</Tooltip> : ''
|
||
}
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<div className="comment_content clearfix" id={`reply_content_${item.id}`}>
|
||
<div className="color-grey-3" id={`reply_content_${item.id}`}>
|
||
<RenderHtml className="break_word_comments" value={item.content} />
|
||
</div>
|
||
</div>
|
||
<div className="childrenCommentsView">
|
||
{(item && item.children && item.children.length) ? <div className="trangle"></div> : ''}
|
||
{this.renderChildenComments(item)}
|
||
{item.isAllChildrenLoaded != true && item.children && this.props.isChildCommentPagination == true && item.child_message_count > 5 ?
|
||
<Tooltip title={"点击查看更多回复"} disableFocusListener={true}>
|
||
<div className="loadMoreChildComments" onClick={() => { this.props.loadMoreChildComments && this.props.loadMoreChildComments(item) }}>
|
||
<i className="iconfont icon-xiajiantou"></i>
|
||
</div>
|
||
</Tooltip>
|
||
: ''}
|
||
</div>
|
||
{/*mr10 */}
|
||
<p className="fr orig_reply">
|
||
<span id="hidden_discuss_btn_952">
|
||
</span>
|
||
{(this.props.power) ?
|
||
<a href="javascript:void(0);" className="color-grey-8" onClick={() => { this.putTop(item.id, !item.sticky) }}>
|
||
<Tooltip title={item.sticky ? "取消置顶" : "置顶"} disableFocusListener={true}>
|
||
<i className="iconfont icon-zhiding mr5" style={item.sticky ? { transform: "rotate(180deg)", display: "inline-block" } : undefined}></i>
|
||
</Tooltip>
|
||
</a> : null}
|
||
{/* && !item.reward */}
|
||
{this.props.showRewardButton != false && item.admin === true ?
|
||
<a className="color-grey-8 fl mt2" onClick={() => this.showGoldRewardDialog(item)}>
|
||
<Tooltip title={"给TA奖励金币"} disableFocusListener={true}>
|
||
<i className="iconfont icon-jiangli mr5 fl"></i>
|
||
</Tooltip>
|
||
</a>
|
||
: ""}
|
||
|
||
{this.props.showHiddenButton == true
|
||
&& (this.props.onlySuperAdminCouldHide && item.isSuperAdmin || !this.props.onlySuperAdminCouldHide && item.admin === true) ?
|
||
<Tooltip title={item.hidden ? "取消隐藏" : "隐藏评论"} disableFocusListener={true}>
|
||
<a className="color-grey-8 fl mt1" onClick={() => this.onCommentBtnClick(item, '', item.hidden ? 'hiddenCancel' : 'hidden')}>
|
||
<i className={` ${item.hidden ? 'iconfont icon-yincangbiyan' : 'fa fa-eye'} mr5`}></i>
|
||
</a>
|
||
</Tooltip>
|
||
: ""}
|
||
{item.admin && (!item.children || item.children.length === 0) ?
|
||
<a className="color-grey-8" onClick={() => this.onCommentBtnClick(item, '', 'delete')}>
|
||
<Tooltip title={"删除"} disableFocusListener={true}>
|
||
<i className="iconfont icon-shanchu mr5"></i>
|
||
</Tooltip>
|
||
</a> : ''}
|
||
|
||
{(this.props.showReply == undefined || this.props.showReply == true) && <a className="color-grey-8"
|
||
onClick={() => this.initReply(item)} >
|
||
<Tooltip title={"回复"}>
|
||
<i className="iconfont icon-huifu1 mr5"></i>
|
||
</Tooltip>
|
||
</a>}
|
||
|
||
<span className="reply_praise_count_952">
|
||
<Tooltip title={item.user_praise ? "取消点赞" : "点赞"}>
|
||
<a className={`fr mr5 ${item.user_praise ? 'color-orange03' : 'color-grey-8'}`} onClick={() => commentPraise(item.id)}>
|
||
<i className={item.user_praise ? "iconfont icon-dianzan mr3" : "iconfont icon-dianzan-xian mr3"}></i>
|
||
|
||
<span className="fr font-14" style={{ marginTop: '1px' }}>{item.praise_count ? item.praise_count : ''}</span>
|
||
</a>
|
||
</Tooltip>
|
||
</span>
|
||
</p>
|
||
<CommentItemMDEditor showReplyEditorFlag={showReplyEditorFlag}
|
||
currentReplyComment={currentReplyComment}
|
||
item={item}
|
||
user={user}
|
||
replyComment={replyComment}
|
||
tabIndexChange={tabIndexChange}
|
||
|
||
buttonText={this.props.buttonText}
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)
|
||
})
|
||
return commentsElement;
|
||
}
|
||
|
||
onCommentBtnClick(comment, childComment, dialogType) {
|
||
this.comment = comment;
|
||
this.childComment = childComment;
|
||
this.setState({ dialogOpen: true, dialogType: dialogType })
|
||
}
|
||
handleDialogClose() {
|
||
this.setState({
|
||
dialogOpen: false
|
||
})
|
||
}
|
||
onDialogOkBtnClick = () => {
|
||
|
||
const { deleteComment, hiddenComment } = this.props;
|
||
const { dialogType } = this.state;
|
||
if (dialogType === 'delete') {
|
||
deleteComment(this.comment, this.childComment ? this.childComment.id : '')
|
||
} else if (dialogType === 'hidden' || dialogType === 'hiddenCancel') {
|
||
hiddenComment(this.comment, this.childComment ? this.childComment.id : '')
|
||
}
|
||
|
||
this.setState({ dialogOpen: false })
|
||
}
|
||
|
||
showGoldRewardDialog(comment, childComment) {
|
||
if (comment.admin === true) {
|
||
this.comment = comment;
|
||
this.childComment = childComment;
|
||
this.setState({ goldRewardDialogOpen: true })
|
||
}
|
||
}
|
||
handleGoldRewardDialogClose() {
|
||
this.setState({
|
||
goldRewardDialogOpen: false
|
||
})
|
||
}
|
||
onGoldRewardDialogOkBtnClick() {
|
||
const { goldRewardInput } = this.state;
|
||
if (!goldRewardInput || goldRewardInput === '0') {
|
||
this.setState({ goldRewardInputError: true })
|
||
return;
|
||
} else {
|
||
this.setState({ goldRewardDialogOpen: false })
|
||
this.props.rewardCode(this.comment, this.childComment, goldRewardInput)
|
||
}
|
||
}
|
||
onGoldRewardInputChange(value) {
|
||
// e.target.value
|
||
const number = parseInt(value || 0, 10);
|
||
if (Number.isNaN(number)) {
|
||
return;
|
||
}
|
||
this.setState({ goldRewardInput: number, goldRewardInputError: false });
|
||
}
|
||
render() {
|
||
const { deleteComment, onPaginationChange, comment_count_without_reply, currentPage, comments, usingAntdModal } = this.props;
|
||
const { dialogOpen, goldRewardDialogOpen, dialogType, goldRewardInputError } = this.state;
|
||
|
||
return (
|
||
<div className="fit -scroll" style={{ 'overflowX': 'hidden' }}>
|
||
<Modals
|
||
modalsType={dialogOpen}
|
||
modalsTopval={
|
||
dialogType === 'delete' ? '确定要删除该条回复吗?'
|
||
: dialogType === 'hidden' ? '确定要隐藏该条回复吗?'
|
||
: dialogType === 'hiddenCancel' ? '确定要取消隐藏该条回复吗?' : ''
|
||
}
|
||
modalsBottomval={""}
|
||
modalCancel={this.handleDialogClose}
|
||
modalSave={this.onDialogOkBtnClick}
|
||
>
|
||
</Modals>
|
||
<Modal
|
||
width={400}
|
||
title="奖励设置"
|
||
bodyStyle={{ textAlign: 'center' }}
|
||
visible={goldRewardDialogOpen}
|
||
onCancel={this.handleGoldRewardDialogClose}
|
||
onOk={() => this.onGoldRewardDialogOkBtnClick()}
|
||
>
|
||
<InputNumber placeholder="请输入奖励的金币数量" id="goldReward" type="number" value={this.state.goldRewardInput}
|
||
onChange={(e) => this.onGoldRewardInputChange(e)} width={228} style={{ width: '228px' }} />
|
||
</Modal>
|
||
|
||
<div className="-layout-v -fit">
|
||
<div className="panel-comment_item" >
|
||
|
||
{this.renderComments()}
|
||
|
||
</div>
|
||
{(comment_count_without_reply > 10) ?
|
||
<div className="pagination-contaner">
|
||
<Pagination showQuickJumper onChange={onPaginationChange} current={currentPage} total={comment_count_without_reply} />
|
||
</div>
|
||
: ''}
|
||
{(comment_count_without_reply == 0) ? <div>
|
||
|
||
<div className="edu-tab-con-box clearfix edu-txt-center">
|
||
<img className="edu-nodata-img mb20"
|
||
src={getImageUrl("images/educoder/nodata.png")} />
|
||
<p className="edu-nodata-p mb20">暂时还没有相关数据哦!</p>
|
||
</div>
|
||
</div>
|
||
: ''}
|
||
</div>
|
||
|
||
</div>
|
||
)
|
||
}
|
||
}
|
||
|
||
export default Comments; |