import React, { Component } from "react"; import PropTypes from "prop-types"; import { message, Tag } from "antd"; import axios from "./axios"; import { ERROR_DEFAULT, LIMIT } from "./constant"; import { CommentContext } from "./Comment"; import { isFunction } from "./helper"; import CommentInput from "./components/CommentInput"; import CommentList from "./components/CommentList"; import Editor from "./components/Editor"; import lang from "./lang"; import "./App.css"; class App extends Component { constructor(props) { super(props); this.state = { loading: {}, // oss 配置 oss: {}, // 评论数据 list: [], page: 1, total: 0, // 是否没有更多评论了 isNoMoreComment: false }; this.handleChangeLoading = this.handleChangeLoading.bind(this); this.sGetComment = this.sGetComment.bind(this); this.sGetReply = this.sGetReply.bind(this); this.sCreateComment = this.sCreateComment.bind(this); this.sCreateReply = this.sCreateReply.bind(this); this.sCommentFavor = this.sCommentFavor.bind(this); this.sReplyFavor = this.sReplyFavor.bind(this); this.sOssSts = this.sOssSts.bind(this); } componentDidMount() {} /** * 改变 loading 状态 * @param {string} key key * @param {string} value value */ handleChangeLoading(key, value) { const { loading } = this.state; loading[key] = value; this.setState({ loading }); } /** * 获取评论列表 */ sGetComment({ page = 1 } = {}) { this.handleChangeLoading("sGetComment", true); const { API, type, businessId } = this.props; axios .get( `${API}/comments?type=${type}&business_id=${businessId}&page=${page}&limit=${LIMIT}` ) .then(response => { const { list, page, total } = response.data; if (list) { let newList = list; if (page > 1) { let { list: oldList } = this.state; // 删除临时数据 oldList = oldList.filter(o => !o.isTemporary); newList = oldList.concat(newList); } this.setState({ list: newList, page, total }); } else { message.info("没有更多评论了"); this.setState({ isNoMoreComment: true }); } }) .catch(error => { if (error.response && error.response.data && error.response.data.msg) { message.error(lang[error.response.data.msg] || ERROR_DEFAULT); return; } message.error(lang[error.message] || ERROR_DEFAULT); }) .finally(() => { this.handleChangeLoading("sGetComment", false); }); } /** * 获取更多回复 */ sGetReply({ commentId, page = 1 } = {}) { this.handleChangeLoading("sGetReply", true); const { API } = this.props; axios .get(`${API}/replies?comment_id=${commentId}&page=${page}&limit=${LIMIT}`) .then(response => { if (!response.data.list) { message.info("没有更多数据了!"); } const list = this.state.list.map(item => { if (item.id === commentId) { if (!item.replies) item.replies = []; if (response.data.list) { if (page === 1) { // 如果当前页数为第一页,则清空当前所有的 replies // 并将获取到的 replies 存放在 state item.replies = response.data.list; } else { item.replies = item.replies .filter(o => !o.isTemporary) .concat(response.data.list); // 如果当前页数非第一页,则合并 replies } item.reply_count = response.data.total; item.reply_page = response.data.page; } else { item.isNoMoreReply = true; } } return item; }); this.setState({ list }); }) .catch(error => { if (error.response && error.response.data && error.response.data.msg) { message.error(lang[error.response.data.msg] || ERROR_DEFAULT); return; } message.error(lang[error.message] || ERROR_DEFAULT); }) .finally(() => { this.handleChangeLoading("sGetReply", false); }); } /** * 添加评论 * @param {object} {content} comment content */ sCreateComment({ content } = {}) { if (!content) return message.error("评论内容不能为空 "); this.handleChangeLoading("sCreateComment", true); const { API, type, businessId } = this.props; axios(`${API}/comments`, { method: "post", data: { type, business_id: businessId, content }, withCredentials: true }) .then(response => { message.success("评论成功!"); // 将数据写入到 list 中 // 临时插入 // 等到获取数据之后,删除临时数据 const { list, total } = this.state; list.unshift({ ...response.data, isTemporary: true // 临时的数据 }); this.setState({ list, total: total + 1 }); }) .catch(error => { if (error.response && error.response.data && error.response.data.msg) { message.error(lang[error.response.data.msg] || ERROR_DEFAULT); return; } message.error(lang[error.message] || ERROR_DEFAULT); }) .finally(() => { this.handleChangeLoading("sCreateComment", false); }); } /** * 添加回复 * 回复评论/回复回复 * @param {object} data { comment_id, content, [reply_id] } */ sCreateReply(data, cb) { console.log("list: ", this.state.list); if (!data.content) return message.error("回复内容不能为空 "); this.handleChangeLoading("sCreateReply", true); const { API } = this.props; axios(`${API}/replies`, { method: "post", data, withCredentials: true }) .then(response => { message.success("回复成功!"); if (isFunction(cb)) cb(); // 将数据写入到 list 中 // 临时插入 // 等到获取数据之后,删除临时数据 const list = this.state.list.map(item => { if (item.id === data.comment_id) { if (!item.replies) item.replies = []; item.replies.push({ ...response.data, isTemporary: true // 临时的数据 }); item.reply_count += 1; } return item; }); this.setState({ list }); }) .catch(error => { if (error.response && error.response.data && error.response.data.msg) { message.error(lang[error.response.data.msg] || ERROR_DEFAULT); return; } message.error(lang[error.message] || ERROR_DEFAULT); }) .finally(() => { this.handleChangeLoading("sCreateReply", false); }); } /** * 评论 点赞/取消点赞 * @param {string} commentId { commentId } * @param {boolean} favored 是否已经点过赞 */ sCommentFavor(commentId, favored) { this.handleChangeLoading("sCommentFavor", true); const { API } = this.props; axios(`${API}/comments/${commentId}/favor`, { method: favored ? "delete" : "put", withCredentials: true }) .then(response => { message.success(favored ? "取消点赞成功!" : "点赞成功!"); // 更新 list 中的该项数据的 favored const list = this.state.list.map(item => { if (item.id === commentId) { item.favored = !favored; item.favor_count += favored ? -1 : 1; } return item; }); this.setState({ list }); }) .catch(error => { if (error.response && error.response.data && error.response.data.msg) { message.error(lang[error.response.data.msg] || ERROR_DEFAULT); return; } message.error(lang[error.message] || ERROR_DEFAULT); }) .finally(() => { this.handleChangeLoading("sCommentFavor", false); }); } /** * 回复 点赞/取消点赞 * @param {string} replyId replyId * @param {string} commentId commentId * @param {boolean} favored 是否已经点过赞 */ sReplyFavor(replyId, commentId, favored) { this.handleChangeLoading("sReplyFavor", true); console.log("replyId, commentId ", replyId, commentId); const { API } = this.props; axios(`${API}/replies/${replyId}/favor`, { method: favored ? "delete" : "put", withCredentials: true }) .then(response => { console.log("response: ", response); message.success(favored ? "取消点赞成功!" : "点赞成功!"); // TODO: (2018.07.20 node) 对评论的回复点赞,报错 // // 更新 list 中的该项数据的 favored // const list = this.state.list.map(item => { // if (item.id === replyId) { // item.favored = !favored; // item.favor_count += favored ? -1 : 1; // } // return item; // }); // this.setState({ list }); }) .catch(error => { if (error.response && error.response.data && error.response.data.msg) { message.error(lang[error.response.data.msg] || ERROR_DEFAULT); return; } message.error(lang[error.message] || ERROR_DEFAULT); }) .finally(() => { this.handleChangeLoading("sReplyFavor", false); }); } /** * 获取 OSS 上传的参数 */ sOssSts() { this.handleChangeLoading("sOssSts", true); const { API } = this.props; axios .get(`${API}/oss/sts`) .then(response => { this.setState({ oss: { ...response.data } }); }) .catch(error => { if (error.response && error.response.data && error.response.data.msg) { message.error(lang[error.response.data.msg] || ERROR_DEFAULT); return; } message.error(lang[error.message] || ERROR_DEFAULT); }) .finally(() => { this.handleChangeLoading("sOssSts", false); }); } render() { // 添加到 Context 的数据 const value = { ...this.state, ...this.props, sCreateComment: this.sCreateComment, sGetComment: this.sGetComment, sCommentFavor: this.sCommentFavor, sReplyFavor: this.sReplyFavor, sCreateReply: this.sCreateReply, sGetReply: this.sGetReply, sOssSts: this.sOssSts }; return (
{this.props.showHeader && (
留言 口碑 (全站挑出毛病或提出合理建议,奖励10到100元红包)
)} {this.props.showEditor && ( )} {this.props.showList && (
)}
); } } App.propTypes = { type: PropTypes.number.isRequired, // 评论的 type businessId: PropTypes.string.isRequired, // 评论的 business_id API: PropTypes.string, // 评论的 API 前缀 showList: PropTypes.bool, // 是否显示评论列表 showEditor: PropTypes.bool, // 是否显示评论输入框 showHeader: PropTypes.bool // 是否显示评论顶部的提示 }; App.defaultProps = { API: "http://api.links123.net/comment/v1", showList: true, showEditor: true, showHeader: true }; export { Editor }; export default App;