通用评论

App.js 8.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. import React, { Component } from "react";
  2. import { message } from "antd";
  3. import axios from "./axios";
  4. import { URL, ERROR_DEFAULT, LIMIT } from "./constant";
  5. import { CommentContext } from "./Comment";
  6. import { isFunction } from "./helper";
  7. import CommentInput from "./components/CommentInput";
  8. import CommentList from "./components/CommentList";
  9. // import * as mock from "./mock";
  10. import "./App.css";
  11. class App extends Component {
  12. constructor(props) {
  13. super(props);
  14. this.state = {
  15. loading: {},
  16. // oss 配置
  17. oss: {},
  18. // 评论数据
  19. list: [],
  20. page: 1,
  21. total: 0,
  22. // 是否没有更多评论了
  23. isNoMoreComment: false
  24. };
  25. this.handleChangeLoading = this.handleChangeLoading.bind(this);
  26. this.sGetComment = this.sGetComment.bind(this);
  27. this.sGetReply = this.sGetReply.bind(this);
  28. this.sCreateComment = this.sCreateComment.bind(this);
  29. this.sCreateReply = this.sCreateReply.bind(this);
  30. this.sCommentFavor = this.sCommentFavor.bind(this);
  31. this.sOssSts = this.sOssSts.bind(this);
  32. }
  33. componentDidMount() {
  34. this.sGetComment();
  35. }
  36. /**
  37. * 改变 loading 状态
  38. * @param {string} key key
  39. * @param {string} value value
  40. */
  41. handleChangeLoading(key, value) {
  42. const { loading } = this.state;
  43. loading[key] = value;
  44. this.setState({ loading });
  45. }
  46. /**
  47. * 获取评论列表
  48. */
  49. sGetComment({ type = 1, businessId = 1, page = 1 } = {}) {
  50. this.handleChangeLoading("sGetComment", true);
  51. // 测试数据列表
  52. // const { comments } = mock;
  53. // this.setState({
  54. // list: comments.list,
  55. // page: 1,
  56. // total: 100
  57. // });
  58. // this.handleChangeLoading("sGetComment", false);
  59. // return;
  60. axios
  61. .get(
  62. `${URL}/comments?type=${type}&business_id=${businessId}&page=${page}&limit=${LIMIT}`
  63. )
  64. .then(response => {
  65. const { list, page, total } = response.data;
  66. if (list) {
  67. let newList = list;
  68. if (page > 1) {
  69. let { list: oldList } = this.state;
  70. // 删除临时数据
  71. oldList = oldList.filter(o => !o.isTemporary);
  72. newList = oldList.concat(newList);
  73. }
  74. this.setState({
  75. list: newList,
  76. page,
  77. total
  78. });
  79. } else {
  80. message.info("没有更多评论了");
  81. this.setState({
  82. isNoMoreComment: true
  83. });
  84. }
  85. })
  86. .catch(error => {
  87. if (error.response && error.response.data && error.response.data.msg) {
  88. message.error(error.response.data.msg || ERROR_DEFAULT);
  89. return;
  90. }
  91. message.error(error.message || ERROR_DEFAULT);
  92. })
  93. .finally(() => {
  94. this.handleChangeLoading("sGetComment", false);
  95. });
  96. }
  97. /**
  98. * 获取更多回复
  99. */
  100. sGetReply({ commentId, page = 1 } = {}) {
  101. this.handleChangeLoading("sGetReply", true);
  102. axios
  103. .get(`${URL}/replies?comment_id=${commentId}&page=${page}&limit=${LIMIT}`)
  104. .then(response => {
  105. const { list: replies } = response.data;
  106. if (!replies) {
  107. message.info("没有更多数据了!");
  108. }
  109. const list = this.state.list.map(item => {
  110. if (item.id === commentId) {
  111. if (!item.replies) item.replies = [];
  112. if (replies) {
  113. if (page === 1) {
  114. // 如果当前页数为第一页,则清空当前所有的 replies
  115. // 并将获取到的 replies 存放在 state
  116. item.replies = replies;
  117. } else {
  118. item.replies = item.replies.concat(replies);
  119. // 如果当前页数非第一页,则合并 replies
  120. }
  121. } else {
  122. item.isNoMoreReply = true;
  123. }
  124. }
  125. return item;
  126. });
  127. this.setState({ list });
  128. })
  129. .catch(error => {
  130. if (error.response && error.response.data && error.response.data.msg) {
  131. message.error(error.response.data.msg || ERROR_DEFAULT);
  132. return;
  133. }
  134. message.error(error.message || ERROR_DEFAULT);
  135. })
  136. .finally(() => {
  137. this.handleChangeLoading("sGetReply", false);
  138. });
  139. }
  140. /**
  141. * 添加评论
  142. * @param {object} data { type, business_id, content }
  143. */
  144. sCreateComment(data) {
  145. if (!data.content) return message.error("评论内容不能为空 ");
  146. this.handleChangeLoading("sCreateComment", true);
  147. axios(`${URL}/comments`, {
  148. method: "post",
  149. data,
  150. withCredentials: true
  151. })
  152. .then(response => {
  153. message.success("评论成功!");
  154. // 将数据写入到 list 中
  155. // 临时插入
  156. // 等到获取数据之后,删除临时数据
  157. const { list } = this.state;
  158. list.unshift({
  159. ...response.data,
  160. isTemporary: true // 临时的数据
  161. });
  162. this.setState({ list });
  163. })
  164. .catch(error => {
  165. if (error.response && error.response.data && error.response.data.msg) {
  166. message.error(error.response.data.msg || ERROR_DEFAULT);
  167. return;
  168. }
  169. message.error(error.message || ERROR_DEFAULT);
  170. })
  171. .finally(() => {
  172. this.handleChangeLoading("sCreateComment", false);
  173. });
  174. }
  175. /**
  176. * 添加回复
  177. * 回复评论/回复回复
  178. * @param {object} data { comment_id, content, [reply_id] }
  179. */
  180. sCreateReply(data, cb) {
  181. if (!data.content) return message.error("回复内容不能为空 ");
  182. this.handleChangeLoading("sCreateReply", true);
  183. axios(`${URL}/replies`, {
  184. method: "post",
  185. data,
  186. withCredentials: true
  187. })
  188. .then(response => {
  189. // console.log("response: ", response.data);
  190. // // 将该条数据插入到 list 中
  191. // const list = this.state.list.map(item => {
  192. // if (item.id === data.comment_id) {
  193. // if (!item.replies) item.replies = [];
  194. // item.reply_count += 1
  195. // item.replies.unshift(response.data);
  196. // }
  197. // return item;
  198. // });
  199. // this.setState({ list });
  200. this.sGetReply({ commentId: data.comment_id });
  201. message.success("回复成功!");
  202. if (isFunction(cb)) cb();
  203. })
  204. .catch(error => {
  205. if (error.response && error.response.data && error.response.data.msg) {
  206. message.error(error.response.data.msg || ERROR_DEFAULT);
  207. return;
  208. }
  209. message.error(error.message || ERROR_DEFAULT);
  210. })
  211. .finally(() => {
  212. this.handleChangeLoading("sCreateReply", false);
  213. });
  214. }
  215. /**
  216. * 点赞/取消点赞
  217. * @param {string} commentId { commentId }
  218. * @param {boolean} favored 是否已经点过赞
  219. */
  220. sCommentFavor(commentId, favored) {
  221. this.handleChangeLoading("sCommentFavor", true);
  222. axios(`${URL}/comments/${commentId}/favor`, {
  223. method: favored ? "delete" : "put",
  224. withCredentials: true
  225. })
  226. .then(response => {
  227. message.success(favored ? "取消点赞成功!" : "点赞成功!");
  228. // 更新 list 中的该项数据的 favored
  229. const list = this.state.list.map(item => {
  230. if (item.id === commentId) {
  231. item.favored = !favored;
  232. item.favor_count += favored ? -1 : 1;
  233. }
  234. return item;
  235. });
  236. this.setState({ list });
  237. })
  238. .catch(error => {
  239. if (error.response && error.response.data && error.response.data.msg) {
  240. message.error(error.response.data.msg || ERROR_DEFAULT);
  241. return;
  242. }
  243. message.error(error.message || ERROR_DEFAULT);
  244. })
  245. .finally(() => {
  246. this.handleChangeLoading("sCommentFavor", false);
  247. });
  248. }
  249. /**
  250. * 获取 OSS 上传的参数
  251. */
  252. sOssSts() {
  253. this.handleChangeLoading("sOssSts", true);
  254. axios
  255. .get(`${URL}/oss/sts`)
  256. .then(response => {
  257. this.setState({ oss: { ...response.data } });
  258. })
  259. .catch(error => {
  260. if (error.response && error.response.data && error.response.data.msg) {
  261. message.error(error.response.data.msg || ERROR_DEFAULT);
  262. return;
  263. }
  264. message.error(error.message || ERROR_DEFAULT);
  265. })
  266. .finally(() => {
  267. this.handleChangeLoading("sOssSts", false);
  268. });
  269. }
  270. render() {
  271. // 添加到 Context 的数据
  272. const value = {
  273. ...this.state,
  274. sCreateComment: this.sCreateComment,
  275. sGetComment: this.sGetComment,
  276. sCommentFavor: this.sCommentFavor,
  277. sCreateReply: this.sCreateReply,
  278. sGetReply: this.sGetReply,
  279. sOssSts: this.sOssSts
  280. };
  281. return (
  282. <CommentContext.Provider value={value}>
  283. <div className="comment">
  284. <CommentInput />
  285. <div style={{ marginTop: 20 }}>
  286. <CommentList />
  287. </div>
  288. </div>
  289. </CommentContext.Provider>
  290. );
  291. }
  292. }
  293. export default App;