通用评论

index.js 3.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import React, { Component } from "react";
  2. import PropTypes from "prop-types";
  3. import { Avatar, Icon } from "antd";
  4. import dayjs from "dayjs";
  5. import Comment from "../../Comment";
  6. import CommentInput from "../CommentInput";
  7. import avatar from "../../avatar";
  8. import { renderContent } from "../../helper";
  9. import "./index.css";
  10. class CommentItem extends Component {
  11. constructor(props) {
  12. super(props);
  13. this.state = {
  14. showInput: false
  15. };
  16. this.handleToggleInput = this.handleToggleInput.bind(this);
  17. this.renderTextWithReply = this.renderTextWithReply.bind(this);
  18. }
  19. handleToggleInput() {
  20. this.setState({ showInput: !this.state.showInput });
  21. }
  22. renderTextWithReply(text, content) {
  23. let newText = text;
  24. const { reply } = content;
  25. if (reply) {
  26. newText = `${newText} //@<a href="/${reply.user_id}">${
  27. reply.user_name
  28. }</a> ${reply.content}`;
  29. if (reply.reply) {
  30. return this.renderTextWithReply(newText, reply);
  31. }
  32. }
  33. return newText;
  34. }
  35. render() {
  36. const {
  37. commentId,
  38. replyId,
  39. content,
  40. action,
  41. showReply,
  42. onShowReply,
  43. app
  44. } = this.props;
  45. const { showInput } = this.state;
  46. return (
  47. <div className="box">
  48. <div className="left">
  49. <Avatar src={content.user_avatar || avatar} size="large" />
  50. </div>
  51. <div className="right">
  52. <div className="name">
  53. <a href={`/${content.user_id}`}>
  54. {content.user_name || "暂无昵称"}
  55. </a>
  56. <span style={{ marginLeft: 10 }}>
  57. {dayjs(content.created * 1000).format("YYYY-MM-DD HH:mm:ss")}
  58. </span>
  59. </div>
  60. <div
  61. className="content"
  62. dangerouslySetInnerHTML={{
  63. __html: renderContent(
  64. this.renderTextWithReply(content.content, content)
  65. )
  66. }}
  67. />
  68. <div className="bottom">
  69. {content.reply_count ? (
  70. <div>
  71. <a
  72. className="itemLeft"
  73. onClick={onShowReply}
  74. style={{ userSelect: "none" }}
  75. >
  76. {content.reply_count} 条回复
  77. {showReply ? <Icon type="up" /> : <Icon type="down" />}
  78. </a>
  79. </div>
  80. ) : null}
  81. <a onClick={this.handleToggleInput} className="itemRight">
  82. &nbsp; 回复
  83. </a>
  84. <div
  85. className="itemRight"
  86. style={{ cursor: "pointer" }}
  87. onClick={() => {
  88. if (replyId) {
  89. // 如果有 replyId,则说明是评论的回复
  90. app.sReplyFavor(content.id, commentId, content.favored);
  91. return;
  92. }
  93. app.sCommentFavor(content.id, content.favored);
  94. }}
  95. >
  96. <Icon
  97. type="like-o"
  98. className={content.favored ? "favored" : ""}
  99. />
  100. &nbsp;{content.favor_count}
  101. </div>
  102. </div>
  103. </div>
  104. {showInput && (
  105. <CommentInput
  106. content={app.children}
  107. action={action}
  108. replyId={replyId}
  109. commentId={commentId}
  110. callback={this.handleToggleInput}
  111. />
  112. )}
  113. </div>
  114. );
  115. }
  116. }
  117. CommentItem.propTypes = {
  118. content: PropTypes.object.isRequired,
  119. // comment 评论
  120. // reply 评论的回复
  121. // replyToReply 回复的回复
  122. action: PropTypes.oneOf(["comment", "reply", "replyToReply"]),
  123. onShowReply: PropTypes.func
  124. };
  125. CommentItem.defaultProps = {
  126. action: "comment",
  127. onShowReply: () => {}
  128. };
  129. export default Comment(CommentItem);