通用评论 vedio

index.js 8.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. import React, { Component } from "react";
  2. import PropTypes from "prop-types";
  3. import { Avatar, Icon, Tooltip, Popconfirm } from "antd";
  4. import dayjs from "dayjs";
  5. import "dayjs/locale/zh-cn";
  6. // import 'dayjs/locale/es';
  7. import relativeTime from "dayjs/plugin/relativeTime";
  8. import intl from "react-intl-universal";
  9. import Comment from "../../Comment";
  10. import CommentInput from "../CommentInput";
  11. import avatar from "../../avatar";
  12. import { renderContent } from "../../helper";
  13. import { IMAGE_SPLIT } from "../../constant";
  14. import "./index.css";
  15. import ImagePreviewer from "../ImagePreviewer/ImagePreviewer";
  16. // dayjs.locale("zh-cn");
  17. dayjs.extend(relativeTime);
  18. class CommentItem extends Component {
  19. constructor(props) {
  20. super(props);
  21. this.state = {
  22. showInput: false,
  23. showPreviewer: false,
  24. previewerIndex: 0
  25. };
  26. this.handleToggleInput = this.handleToggleInput.bind(this);
  27. this.renderTextWithReply = this.renderTextWithReply.bind(this);
  28. this.showPreviewer = this.showPreviewer.bind(this);
  29. this.hidePreviewer = this.hidePreviewer.bind(this);
  30. }
  31. showPreviewer(index) {
  32. this.setState({
  33. showPreviewer: true,
  34. previewerIndex: index
  35. });
  36. }
  37. hidePreviewer() {
  38. this.setState({
  39. showPreviewer: false
  40. });
  41. }
  42. handleToggleInput() {
  43. this.setState({ showInput: !this.state.showInput });
  44. }
  45. renderTextWithReply(text, content) {
  46. let newText = text;
  47. const { reply } = content;
  48. if (reply) {
  49. // newText = `${newText} //@<a href="/${reply.user_id}">${
  50. // reply.user_name
  51. // }</a> ${reply.content}`;
  52. newText = `${newText} //@${reply.user_name} ${reply.content}`;
  53. // newText = (
  54. // <span>
  55. // {newText}
  56. // @<a href={`/${reply.user_id}`}>{reply.user_name}</a>{reply.content}
  57. // </span>
  58. // )
  59. if (reply.reply) {
  60. return this.renderTextWithReply(newText, reply);
  61. }
  62. }
  63. return newText;
  64. }
  65. render() {
  66. const {
  67. commentId,
  68. replyId,
  69. content,
  70. action,
  71. showReply,
  72. onShowReply,
  73. app
  74. } = this.props;
  75. const { showInput } = this.state;
  76. let newContent = content.content;
  77. let images = "";
  78. if (newContent.indexOf(IMAGE_SPLIT) !== -1) {
  79. newContent = newContent.split(IMAGE_SPLIT);
  80. images = newContent.pop();
  81. newContent = newContent.join("");
  82. }
  83. const imageList = images.split(",");
  84. // 在3, 7前需要换行
  85. const needClear =
  86. imageList.length === 5 ||
  87. imageList.length === 6 ||
  88. imageList.length === 9;
  89. const imgs = [...imageList];
  90. if (needClear) {
  91. if (imgs.length > 6) {
  92. imgs.splice(3, 0, { type: "divider" });
  93. imgs.splice(7, 0, { type: "divider" });
  94. } else {
  95. imgs.splice(3, 0, { type: "divider" });
  96. }
  97. }
  98. return (
  99. <div className="comment-item-box">
  100. <div className="comment-item-left">
  101. <Avatar src={content.user_avatar || avatar} size="large" />
  102. </div>
  103. <div className="comment-item-right">
  104. <div>
  105. {/* <a href={`/${content.user_id}`}>
  106. {content.user_name || "暂无昵称"}
  107. </a> */}
  108. <strong>{content.user_name || intl.get("comment.tourist")}</strong>
  109. <span style={{ marginLeft: 10 }}>
  110. <Tooltip
  111. placement="top"
  112. title={dayjs(content.created * 1000).format(
  113. "YYYY-MM-DD HH:mm:ss"
  114. )}
  115. >
  116. {dayjs(content.created * 1000).fromNow()}
  117. {/* {dayjs(content.created * 1000).locale('zh-cn').fromNow()} */}
  118. </Tooltip>
  119. </span>
  120. </div>
  121. <div
  122. className="comment-item-content"
  123. dangerouslySetInnerHTML={{
  124. __html: renderContent(
  125. this.renderTextWithReply(newContent, content)
  126. )
  127. }}
  128. />
  129. {// image为空时不渲染comment-item-image
  130. imageList.length > 0 && imageList[0] !== "" && (
  131. <div className="comment-item-image">
  132. {!this.state.showPreviewer &&
  133. imgs.map((item, index) => {
  134. if (item.type === "divider") {
  135. return (
  136. <div className="comment-item-image-wrapper" key={index}>
  137. <div className="comment-img-divider" />
  138. {/* <img src={item} alt={item} className="comment-img" /> */}
  139. </div>
  140. );
  141. }
  142. return (
  143. <div
  144. className="comment-item-image-wrapper"
  145. key={index}
  146. onClick={() => {
  147. let i = index;
  148. if (needClear) {
  149. if (index > 3) {
  150. i -= 1;
  151. }
  152. if (index > 7) {
  153. i -= 1;
  154. }
  155. }
  156. this.showPreviewer(i);
  157. }}
  158. >
  159. <div
  160. style={{ backgroundImage: `url(${item})` }}
  161. className="comment-img-thumbnail"
  162. />
  163. {/* <img src={item} alt={item} className="comment-img" /> */}
  164. </div>
  165. );
  166. })}
  167. {this.state.showPreviewer && (
  168. <ImagePreviewer
  169. list={imageList}
  170. index={this.state.previewerIndex}
  171. onFold={this.hidePreviewer}
  172. />
  173. )}
  174. <div className="clearfix" />
  175. </div>
  176. )}
  177. <div className="comment-item-bottom">
  178. {content.reply_count ? (
  179. <div>
  180. <a className="comment-item-bottom-left" onClick={onShowReply}>
  181. {/* {content.reply_count} 条回复 */}
  182. {intl.get("reply.totalReply", { total: content.reply_count })}
  183. {showReply ? <Icon type="up" /> : <Icon type="down" />}
  184. </a>
  185. </div>
  186. ) : null}
  187. {app.userId === content.user_id && (
  188. <Popconfirm
  189. // title="确定要删除吗?"
  190. title={intl.get("popConfirm.title")}
  191. onConfirm={() => {
  192. if (replyId) {
  193. app.sDeleteReply(content.id, commentId);
  194. return;
  195. }
  196. app.sDeleteComment(content.id);
  197. }}
  198. okText={intl.get("popConfirm.ok")}
  199. cancelText={intl.get("popConfirm.cancel")}
  200. >
  201. <a className="comment-item-bottom-right">
  202. &nbsp; {intl.get("popConfirm.delete")}
  203. </a>
  204. </Popconfirm>
  205. )}
  206. <a
  207. onClick={this.handleToggleInput}
  208. className="comment-item-bottom-right"
  209. >
  210. &nbsp; {intl.get("comment.reply")}
  211. </a>
  212. <div
  213. className="comment-item-bottom-right"
  214. onClick={() => {
  215. if (replyId) {
  216. // 如果有 replyId,则说明是评论的回复
  217. app.sReplyFavor(content.id, commentId, content.favored);
  218. return;
  219. }
  220. app.sCommentFavor(content.id, content.favored);
  221. }}
  222. >
  223. <Icon
  224. type="like-o"
  225. className={
  226. content.favored
  227. ? "comment-favor comment-favored"
  228. : "comment-favor"
  229. }
  230. />
  231. &nbsp;{content.favor_count}
  232. </div>
  233. </div>
  234. </div>
  235. {showInput && (
  236. <CommentInput
  237. content={app.children}
  238. action={action}
  239. replyId={replyId}
  240. commentId={commentId}
  241. callback={this.handleToggleInput}
  242. />
  243. )}
  244. </div>
  245. );
  246. }
  247. }
  248. CommentItem.propTypes = {
  249. content: PropTypes.object.isRequired,
  250. // comment 评论
  251. // reply 评论的回复
  252. // replyToReply 回复的回复
  253. action: PropTypes.oneOf(["comment", "reply", "replyToReply"]),
  254. onShowReply: PropTypes.func
  255. };
  256. CommentItem.defaultProps = {
  257. action: "comment",
  258. onShowReply: () => {}
  259. };
  260. export default Comment(CommentItem);