forked from Gitlink/forgeplus-react
482 lines
14 KiB
JavaScript
482 lines
14 KiB
JavaScript
import React from 'react'
|
||
import axios from 'axios'
|
||
import { notification } from 'antd'
|
||
import update from 'immutability-helper'
|
||
|
||
import ImageLayer from '../page/layers/ImageLayer'
|
||
|
||
const $ = window.$
|
||
/* 需要的props:
|
||
shixun
|
||
id
|
||
myshixun
|
||
id
|
||
challenge
|
||
id
|
||
user
|
||
"image_url": user.image_url,
|
||
"username": user.username,
|
||
showSnackbar
|
||
|
||
*/
|
||
/*
|
||
这里提供props给WrappedComponent,用于封装特定的state和功能(评论列表)
|
||
不要直接使用this.xxx调用WrappedComponent内的方法,尽量避免互相依赖,封装好后供不同场景使用(tpi、tpm)
|
||
*/
|
||
export function commentHOC(WrappedComponent) {
|
||
// 这里如果extends WrappedComponent 会出现 WrappedComponent mount twice的问题
|
||
return class II extends React.Component {
|
||
constructor(props) {
|
||
super(props)
|
||
|
||
// ------------------------------------
|
||
this.createNewComment = this.createNewComment.bind(this)
|
||
this.fetchCommentIfNotFetched = this.fetchCommentIfNotFetched.bind(this)
|
||
this.replyComment = this.replyComment.bind(this)
|
||
this.deleteComment = this.deleteComment.bind(this)
|
||
this.commentPraise = this.commentPraise.bind(this)
|
||
this.hiddenComment = this.hiddenComment.bind(this)
|
||
this.rewardCode = this.rewardCode.bind(this)
|
||
this.showNewReply = this.showNewReply.bind(this)
|
||
// ------------------------------------
|
||
|
||
this.onPaginationChange = this.onPaginationChange.bind(this)
|
||
|
||
this.state = {
|
||
// 评论
|
||
comments: [],
|
||
comment_count_without_reply: 0,
|
||
// 默认pageSize为10
|
||
currentPage: 1,
|
||
loadingComments: true,
|
||
|
||
// 图片最大化
|
||
showImage: false,
|
||
imageSrc: '',
|
||
}
|
||
}
|
||
|
||
// ----------------------------------------------------------------------------------------------评论 Start
|
||
|
||
// ----------------------------------------------------------------------------------------------评论 Start
|
||
onPaginationChange(page) {
|
||
this.fetchComment(page)
|
||
this.setState({
|
||
currentPage: page,
|
||
});
|
||
}
|
||
/*
|
||
email: "1843820944@qq.com"
|
||
grade: 2138
|
||
image_url: "avatar/User/36497"
|
||
login: "p24891375"
|
||
name: "杨俊男"
|
||
user_url: "/p24891375"
|
||
*/
|
||
handleComments(comments, responseData) {
|
||
comments.forEach(element => {
|
||
if (element.children) {
|
||
this.handleComments(element.children, responseData)
|
||
}
|
||
element.admin = responseData.all
|
||
element.manager = element.manage
|
||
|
||
element.username = element.author.name
|
||
element.user_login = element.author.login
|
||
element.image_url = element.author.image_url
|
||
element.user_id = element.author.user_id
|
||
|
||
});
|
||
}
|
||
responseDataParse(response) {
|
||
const comments = response.data.comments
|
||
this.handleComments(comments, response.data)
|
||
}
|
||
fetchComment(page = 1) {
|
||
const { challenge, shixun, match } = this.props;
|
||
// const url = `/api/v1/shixuns/${shixun.id}/shixun_discusses?page=${page-1}&container_type=Shixun`
|
||
const url =
|
||
`/discusses.json?page=${page - 1}&container_identifier=${shixun && shixun.identifier ?
|
||
shixun.identifier : match.params.shixunId}&container_type=Shixun`
|
||
|
||
this.setState({
|
||
loadingComments: true,
|
||
});
|
||
|
||
|
||
axios.get(url,
|
||
{}
|
||
).then((response) => {
|
||
// test
|
||
|
||
if (response.data) {
|
||
this.responseDataParse(response)
|
||
this.setState({
|
||
comments: response.data.comments,
|
||
comment_count_without_reply: response.data.disscuss_count,
|
||
|
||
currentPage: page,
|
||
loadingComments: false,
|
||
}, () => {
|
||
// keditor代码美化
|
||
window.prettyPrint()
|
||
})
|
||
}
|
||
// console.log(response)
|
||
}).catch((error) => {
|
||
console.log(error)
|
||
})
|
||
}
|
||
// 切换关卡时,清空state
|
||
clearCommentsInState = () => {
|
||
this.setState({ comments: [] })
|
||
}
|
||
fetchCommentIfNotFetched() {
|
||
if (this.state.comments && this.state.comments.length) {
|
||
return;
|
||
}
|
||
// http://localhost:3000/api/v1/shixuns/cz7yw3en/shixun_discusses?page=0
|
||
this.fetchComment();
|
||
}
|
||
// 新增父级评论
|
||
createNewComment(content) {
|
||
|
||
const { challenge, shixun, showSnackbar } = this.props;
|
||
if (!content || content.length === 0) {
|
||
showSnackbar('必须填写内容!')
|
||
return;
|
||
}
|
||
const url = `/discusses.json`
|
||
|
||
if (content != undefined) {
|
||
var beforeImage = content.split("<img");
|
||
var afterImage = content.split("/>");
|
||
if (beforeImage[0] == "" && afterImage[1] == "") {
|
||
window.notice_box('不支持纯图片评论<br/>请在评论中增加文字信息');
|
||
return;
|
||
}
|
||
}
|
||
|
||
let res = axios.post(url, {
|
||
container_type: "Shixun",
|
||
container_id: shixun.id,
|
||
challenge_id: challenge.id,
|
||
content,
|
||
position: challenge.position
|
||
}
|
||
).then((response) => {
|
||
if (response.data.discuss) {
|
||
this.fetchComment()
|
||
}
|
||
}).catch((error) => {
|
||
console.log(error)
|
||
})
|
||
return res;
|
||
}
|
||
_findCommentById(id, arg_comments) {
|
||
let comments;
|
||
if (!arg_comments) {
|
||
comments = this.state.comments;
|
||
} else {
|
||
comments = arg_comments;
|
||
}
|
||
for (let i = 0; i < comments.length; i++) {
|
||
if (id === comments[i].id) {
|
||
return i;
|
||
}
|
||
}
|
||
}
|
||
replyComment(commentContent, id) {
|
||
const { challenge, shixun, user, showSnackbar, match } = this.props;
|
||
|
||
if (!commentContent || commentContent.length === 0) {
|
||
showSnackbar('必须填写内容!')
|
||
return;
|
||
}
|
||
const url = `/discusses/${id}/reply.json`
|
||
if (commentContent) {
|
||
commentContent = commentContent.replace(/(\n<p>\n\t<br \/>\n<\/p>)*$/g, '');
|
||
}
|
||
if (!user.login && user.user_url) {
|
||
const loginAr = user.user_url.split('/')
|
||
user.login = loginAr[loginAr.length - 1]
|
||
}
|
||
let res = axios.post(url, { content: commentContent, "container_id": match.params.shixunId, "container_type": "Shixun", }).then((response) => {
|
||
if (response.data.discuss) {
|
||
let newDiscuss = response.data.discuss;
|
||
let { comments } = this.state;
|
||
var commentIndex = this._findCommentById(id);
|
||
let comment = comments[commentIndex]
|
||
comment = Object.assign({}, comment)
|
||
if (!comment.children) {
|
||
comment.children = []
|
||
} else {
|
||
comment.children = comment.children.slice(0);
|
||
}
|
||
comment.children.push({
|
||
"can_delete": true,
|
||
"content": commentContent,
|
||
|
||
"image_url": user.image_url,
|
||
"username": user.username,
|
||
"user_login": user.login,
|
||
"id": newDiscuss.id,
|
||
"position": newDiscuss.position,
|
||
"time": "1分钟前",
|
||
"praise_count": newDiscuss.praise_count,
|
||
|
||
"user_id": newDiscuss.user_id,
|
||
|
||
})
|
||
|
||
comments = comments.slice(0)
|
||
comments[commentIndex] = comment
|
||
|
||
this.setState({
|
||
comments: comments
|
||
})
|
||
}
|
||
}).catch((error) => {
|
||
console.log(error)
|
||
})
|
||
return res
|
||
}
|
||
hiddenComment(item, childCommentId) {
|
||
const id = item.id
|
||
const { challenge, shixun, user, showSnackbar, match } = this.props;
|
||
const url = `/discusses/${id}/hidden.json`
|
||
|
||
const commentIndex = this._findCommentById(id);
|
||
const { comments } = this.state;
|
||
const comment = Object.assign({}, comments[commentIndex]);
|
||
axios.post(url, {
|
||
hidden: !comment.hidden ? "1" : "0",
|
||
container_identifier: match.params.shixunId || shixun.identifier
|
||
}).then((response) => {
|
||
if (response.data.status === -1) {
|
||
showSnackbar(response.data.message)
|
||
return;
|
||
}
|
||
if (response.data.status === 1) {
|
||
|
||
if (!childCommentId) {
|
||
comment.hidden = !comment.hidden;
|
||
const commentsCopy = this.state.comments.slice(0)
|
||
commentsCopy[commentIndex] = comment
|
||
this.setState({
|
||
comments: commentsCopy
|
||
})
|
||
} else { // TODO 目前子回复没hidden字段
|
||
let childCommentIndex = this._findCommentById(childCommentId, comments[commentIndex].children);
|
||
const childComment = comments[commentIndex].children[childCommentIndex]
|
||
childComment.hidden = !childComment.hidden;
|
||
this.setState({ comments })
|
||
}
|
||
|
||
}
|
||
}).catch((error) => {
|
||
console.log(error)
|
||
})
|
||
}
|
||
deleteComment(parrentComment, childCommentId) {
|
||
const { challenge, shixun } = this.props;
|
||
let deleteCommentId = parrentComment.id
|
||
if (childCommentId) {
|
||
deleteCommentId = childCommentId;
|
||
}
|
||
const url = `/discusses/${deleteCommentId}.json`
|
||
|
||
axios.delete(url).then((response) => {
|
||
if (response.data && response.data.status === 1) {
|
||
const commentIndex = this._findCommentById(parrentComment.id);
|
||
|
||
// https://stackoverflow.com/questions/29527385/removing-element-from-array-in-component-state
|
||
if (!childCommentId) {
|
||
this.setState((prevState) => ({
|
||
comments: update(prevState.comments, { $splice: [[commentIndex, 1]] })
|
||
}))
|
||
|
||
if (this.state.comments.length <= 5) {
|
||
this.fetchComment()
|
||
}
|
||
} else {
|
||
let comments = this.state.comments;
|
||
let newComments = Object.assign({}, comments)
|
||
let childCommentIndex = this._findCommentById(childCommentId, newComments[commentIndex].children);
|
||
newComments[commentIndex].children = update(newComments[commentIndex].children, { $splice: [[childCommentIndex, 1]] })
|
||
this.setState({ newComments })
|
||
}
|
||
}
|
||
}).catch((error) => {
|
||
console.log(error)
|
||
})
|
||
}
|
||
|
||
rewardCode(parrentComment, childComment, amount) {
|
||
const { showSnackbar } = this.props;
|
||
let handleComment = parrentComment
|
||
if (childComment) {
|
||
handleComment = childComment;
|
||
}
|
||
let handleCommentId = handleComment.id;
|
||
const url = `/discusses/${handleCommentId}/reward_code.json`
|
||
|
||
axios.post(url, {
|
||
container_type: 'Discusses',
|
||
score: amount,
|
||
user_id: handleComment.user_id
|
||
}).then((response) => {
|
||
if (response.data && response.data.code) {
|
||
const commentIndex = this._findCommentById(parrentComment.id);
|
||
let { comments } = this.state;
|
||
const newComments = comments.slice(0)
|
||
|
||
if (childComment) {
|
||
const childCommentIndex = this._findCommentById(handleComment.id, parrentComment.children);
|
||
const newChildComment = Object.assign({}, childComment);
|
||
newChildComment.reward = response.data.code
|
||
parrentComment = Object.assign({}, parrentComment)
|
||
parrentComment.children = parrentComment.children.slice(0)
|
||
parrentComment.children[childCommentIndex] = newChildComment
|
||
|
||
newComments[commentIndex] = parrentComment;
|
||
|
||
|
||
} else {
|
||
const newComment = Object.assign({}, newComments[commentIndex]);
|
||
newComment.reward = response.data.code;
|
||
newComments[commentIndex] = newComment;
|
||
}
|
||
this.setState({
|
||
comments: newComments
|
||
})
|
||
}
|
||
}).catch((error) => {
|
||
console.log(error)
|
||
showSnackbar('奖励失败,请联系系统管理员!')
|
||
})
|
||
}
|
||
|
||
// 评论点赞
|
||
commentPraise(discussId) {
|
||
const commentIndex = this._findCommentById(discussId);
|
||
const { comments } = this.state;
|
||
|
||
const { challenge } = this.props;
|
||
const url = `/discusses/${discussId}/plus.json`
|
||
axios.post(url, {
|
||
container_type: 'Discuss', //Discuss
|
||
type: comments[commentIndex].user_praise === true ? 0 : 1, // "踩0;赞1"
|
||
}).then((response) => {
|
||
if (response.data.praise_count === 0 || response.data.praise_count) {
|
||
const newComments = comments.slice(0)
|
||
const comment = Object.assign({}, newComments[commentIndex])
|
||
comment.user_praise = !comment.user_praise;
|
||
comment.praise_count = response.data.praise_count;
|
||
newComments[commentIndex] = comment;
|
||
this.setState({
|
||
comments: newComments
|
||
})
|
||
}
|
||
}).catch((error) => {
|
||
console.log(error)
|
||
})
|
||
}
|
||
|
||
|
||
showNewReply() {
|
||
const { shixun, myshixun } = this.props;
|
||
const commentId = 929 // TODO
|
||
const url = `/api/v1/shixuns/${shixun.id}/anchor?container_type=Shixun&myshixun_id=${myshixun.id}&discuss_id=${commentId}`
|
||
|
||
this.setState({
|
||
loadingComments: true,
|
||
gotNewReply: false,
|
||
|
||
});
|
||
axios.get(url,
|
||
{
|
||
// withCredentials: true
|
||
}
|
||
).then((response) => {
|
||
const data = response.data;
|
||
const new_message = data.new_message;
|
||
|
||
this.setState({
|
||
comments: data.children_list,
|
||
comment_count_without_reply: data.disscuss_count,
|
||
|
||
currentPage: data.page,
|
||
loadingComments: false,
|
||
|
||
}, () => {
|
||
if (response.data.find_status) { // 没找到评论的话,默认会返回第一页的评论
|
||
const comment_J = window.$(`#reply_content_${commentId}`);
|
||
if (comment_J.length) {
|
||
comment_J[0].scrollIntoView()
|
||
comment_J.parents('.comment_item_cont').css('border', '1px solid #4CACFF')
|
||
}
|
||
}
|
||
})
|
||
}).catch((error) => {
|
||
console.log(error)
|
||
})
|
||
}
|
||
|
||
componentDidMount() {
|
||
$(".commentsDelegateParent")
|
||
.delegate(".J_Comment_Reply .comment_content img, .J_Comment_Reply .childrenCommentsView img", "click", (event) => {
|
||
|
||
const imageSrc = event.target.src
|
||
// 非回复里的头像图片; 非emoticons
|
||
if (imageSrc.indexOf('/images/avatars/User') === -1 &&
|
||
imageSrc.indexOf('kindeditor/plugins/emoticons') === -1) {
|
||
this.setState({
|
||
showImage: true,
|
||
imageSrc,
|
||
})
|
||
}
|
||
});
|
||
}
|
||
onImageLayerClose = () => {
|
||
this.setState({
|
||
showImage: false,
|
||
imageSrc: '',
|
||
})
|
||
}
|
||
|
||
showNotification = (description, message = "提示", icon) => {
|
||
const data = {
|
||
message,
|
||
description
|
||
}
|
||
if (icon) {
|
||
data.icon = icon;
|
||
}
|
||
notification.open(data);
|
||
}
|
||
render() {
|
||
return (
|
||
<React.Fragment>
|
||
<ImageLayer {...this.state} onImageLayerClose={this.onImageLayerClose}></ImageLayer>
|
||
|
||
<WrappedComponent {...this.props} {...this.state}
|
||
createNewComment={this.createNewComment}
|
||
fetchCommentIfNotFetched={this.fetchCommentIfNotFetched}
|
||
clearCommentsInState={this.clearCommentsInState}
|
||
replyComment={this.replyComment}
|
||
deleteComment={this.deleteComment}
|
||
commentPraise={this.commentPraise}
|
||
hiddenComment={this.hiddenComment}
|
||
rewardCode={this.rewardCode}
|
||
onPaginationChange={this.onPaginationChange}
|
||
showNotification={this.showNotification}
|
||
newMessage={this.newMessage}
|
||
showNewReply={this.showNewReply}
|
||
></WrappedComponent>
|
||
</React.Fragment>
|
||
|
||
)
|
||
}
|
||
}
|
||
} |