comment-list.vue 5.97 KB
<template>
  <div class="comment-context">
    <p class="comment-line"></p>
    <template v-if="commentCount">
      <p class="comment-title">共{{commentCount}}条评论</p>
      <div class="comment-list">
        <CommentItem
          v-for="comment in commentList"
          :key="comment.parentComment.id"
          :class="'comment-' + comment.parentComment.id"
          :parent-comment="comment.parentComment"
          :children-comments="comment.childrenComments"
          :column-type="columnType"
          :share="share"
          :pos-id="0"
          :article-id="articleId"
          :authorUid="authorUid"
          :commentUid="comment.parentComment.uid"
          @remove-comment="onRemoveComment"
          @on-reply="onReply">
        </CommentItem>
      </div>
      <div v-show="showMore" class="more-comment hover-opacity" @click="onFetch">
        <p class="loading-wrap" v-if="onFetching">
          <Loading :size="20"></Loading>
          &nbsp;&nbsp;加载中
        </p>
        <span v-else>{{moreBtnText}}</span>
      </div>
    </template>
    <CommentEmpty
      :dest-id="articleId"
      :column-type="columnType"
      :article-id="articleId"
      :authorUid="authorUid"
      :add-type="0"
      :user="authorName"
      @on-comment="addCommentByComment"
      v-else>
    </CommentEmpty>
  </div>
</template>

<script>
import { get, forEach, find, findIndex } from 'lodash';
import { Loading } from 'cube-ui';
import { mapState as mapYohoState, mapActions as mapYohoActions, createNamespacedHelpers } from 'vuex';

const { mapActions } = createNamespacedHelpers('comment');

export default {
  name: 'ArticleDetailCommentList',
  props: {
    commentCount: [Number, String],
    articleId: [Number, String],
    columnType: {
      type: Number,
      default: 1001
    },
    share: Boolean,
    hasComment: Boolean,
    authorUid: Number,
    authorName: String
  },
  data() {
    return {
      commentList: [],
      page: 1,
      onFetching: false,
      showMore: false,
      moreCommentNum: 0
    };
  },
  mounted() {
    if (!this.yoho.context.userHeadIco) {
      this.$sdk.getUser().then(user => {
        if (user && user.uid) {
          this.fetchUserProfile();
        }
      });
    }

    this.init();
  },
  computed: {
    ...mapYohoState(['yoho']),
    moreBtnText() {
      if (this.page <= 2 && this.moreCommentNum > 0) {
        return `展开${this.moreCommentNum}条评论`;
      } else {
        return '展开更多评论';
      }
    }
  },
  methods: {
    ...mapYohoActions(['fetchUserProfile']),
    ...mapActions(['fetchCommentList', 'fetchReplayList', 'postComment']),
    init() {
      this.commentList.length = 0;
      this.page = 1;
      this.showMore = false;

      this.onFetch();
    },
    updateMoreCommentNum(list = []) {
      let moreCommentNum = this.commentCount;

      forEach(list, val => {
        val.childrenComments = val.childrenComments || [];
        moreCommentNum -= (val.childrenComments.length + 1);
      });
      this.moreCommentNum = moreCommentNum;
    },
    async onFetch() {
      if (!this.articleId || this.onFetching || (this.page > 1 && !this.showMore)) {
        return;
      }

      this.onFetching = true;

      const result = await this.fetchCommentList({
        destId: this.articleId,
        columnType: this.columnType,
        page: this.page,
        limit: 10
      });

      setTimeout(() => {
        if (result.code === 200) {
          this.showMore = result.data.totalPage > this.page;
          this.commentList = this.commentList.concat(result.data.commentInfos || []);

          if (this.page === 1) {
            this.updateMoreCommentNum(result.data.commentInfos);
          }

          this.page++;
        }

        this.onFetching = false;
      }, this.page > 1 ? 800 : 0);
    },
    async onReply({ comment }) {
      const uid = (await this.$sdk.getUser()).uid;

      forEach(this.commentList, (val) => {
        if (val.parentComment && +val.parentComment.id === +comment.rootId) {
          val.childrenComments.unshift(Object.assign(comment, {
            id: comment.destId,
            destId: this.articleId,
            headIco: this.yoho.context.userHeadIco,
            userName: this.yoho.context.userName,
            uid,
            parentUserName: +val.parentComment.id === +comment.parentId ?
              val.parentComment.userName :
              get(find(val.childrenComments, { id: +comment.parentId }), 'userName', '')
          }));
        }
      });
    },
    async addComment(comment) {
      this.commentList.unshift({
        childrenComments: [],
        parentComment: Object.assign(comment, {
          id: comment.destId,
          destId: this.articleId,
          headIco: this.yoho.context.userHeadIco,
          userName: this.yoho.context.userName,
          uid: (await this.$sdk.getUser()).uid
        })
      });
    },
    addCommentByComment({ comment }) {
      this.addComment(comment);
    },
    onRemoveComment({ commentId }) {
      for (let [index, val] of Object.entries(this.commentList)) {
        if (val.parentComment && +val.parentComment.id === +commentId) {
          this.commentList.splice(index, 1);
          break;
        }

        const childrenIndex = findIndex(val.childrenComments, { id: +commentId });

        if ((+index !== -1) && (childrenIndex !== -1)) {
          this.commentList[index].childrenComments.splice(childrenIndex, 1);
          break;
        }
      }
    }
  },
  components: {
    Loading
  }
};
</script>

<style :lang="scss" scoped>
.comment-line {
  margin: 0 30px;
  border-top: 1px solid #f0f0f0;
}

.comment-title {
  font-size: 28px;
  margin: 0 30px;
  color: #9b9b9b;
  line-height: 80px;
}

.comment-list {
  padding: 20px 30px;
}

.more-comment {
  height: 100px;
  line-height: 1;
  font-size: 28px;
  color: #4a90e2;
  border-top: 1px solid #f0f0f0;
  display: flex;
  align-items: center;
  justify-content: center;

  .loading-wrap {
    display: flex;
    align-items: center;
    justify-content: center;
    color: #999;
  }
}
</style>