article-note.vue 8.78 KB
<template>
  <div class="article-detail-notes">
    <ArticleItemHeader v-if="share" :share="share" :data="authorData" :lazy="lazy" :more="false"
                       @on-follow="onFollowAuthor"></ArticleItemHeader>
    <LayoutHeader v-else ref="header" style="visibility: hidden;"></LayoutHeader>

    <div v-if="data.empty" class="article-empty">
      {{data.emptyTip || '文章不存在或文章被删除'}}
    </div>
    <div v-else class="article-context">
      <VideoPlayer ref="video" v-if="+data.sort === 4" class="note-video" :source="data.videoUrl" :cover="data.coverUrl"
                   :width="data.width" :height="data.height"></VideoPlayer>
      <ArticleItemSlide v-else :thumb="thumb" :share="share" :data="slideData" :slide-index="slideIndex" :lazy="lazy"
                        @on-praise="onPraise" @change="onChangeSlide"></ArticleItemSlide>
      <ProductGroup name="ArticleDetail" :article-id="data.articleId" :pos-id="100" :index="0" :thumb="thumb"
                    v-if="productListData.length" :share="share" :data="productListData" :lazy="lazy"></ProductGroup>

      <div class="context-title">{{data.articleTitle}}</div>

      <ArticleDetailIntro :data="introData" :pos-id="posId"></ArticleDetailIntro>
      <ArticleItemTopics :data="topicsData" :share="share"></ArticleItemTopics>

      <div class="publish-time">
        <span>{{publishTime}}</span>
        <!-- <div v-if="data.articleId && !share" class="more-wrap">
          <i class="iconfont icon-more1" @click="onMore"></i>
        </div> -->
      </div>
      <!-- <ArticleDetailCommentList ref="commentList" v-if="data.articleId"
                                :article-id="data.articleId"
                                :share="share"
                                :comment-count="articleState.commentCount"
                                :has-comment="data.hasComment"
                                :authorUid="data.authorUid"
                                :authorName="data.authorName">
      </ArticleDetailCommentList> -->
    </div>

    <div v-if="listTitle" class="rec-article-title">
      <LayoutTitle>{{listTitle}}</LayoutTitle>
    </div>

    <YohoActionSheet transfer v-if="showCommentAction" ref="commentAction" :full="true" :height="549">
       <Comment ref="comment"
                :destId="data.articleId"
                :popup="true"
                :article-id="data.articleId"
                :commentCount="articleState.commentCount"
                :share="share"
                :pos-id="posId"
                :authorUid="data.authorUid"
                :authorName="data.authorName"
                @on-close="onCloseComment"
                @on-comment="onActionComment"></Comment>
    </YohoActionSheet>

     <YohoActionSheet transfer v-if="showProductListAction" ref="productListAction" :full="true" :height="549">
        <CommentHeader>{{'文中商品'}}</CommentHeader>
        <ProductGroup class="product-list-wrapper" name="ArticleDetail" :article-id="data.articleId" :pos-id="106" :index="0" :thumb="thumb" :inline="false" :model="3"
                      v-if="productListData.length" :share="share" :data="productListData" :lazy="lazy"></ProductGroup>
    </YohoActionSheet>
  </div>
</template>

<script>
import { get } from 'lodash';
import ArticleDetailCommentList from './comment-list';
import ArticleItemHeader from '../article/article-item-header';
import ArticleItemSlide from '../article/article-item-slide';
import ArticleItemTopics from '../article/article-item-topics';
import ArticleDetailIntro from './article-intro';
import dayjs from 'utils/day';
import { createNamespacedHelpers } from 'vuex';

const { mapState } = createNamespacedHelpers('article');

export default {
  name: 'ArticleDetailNote',
  props: {
    data: {
      type: Object,
      default() {
        return {};
      }
    },
    listTitle: String,
    scrollTop: Number,
    scrollTo: Function,
    share: Boolean,
    posId: Number,
  },
  data() {
    return {
      slideIndex: 1,
      commentList: [],
      commentPage: 1,
      commentFetching: false,
      showCommentMore: false,
      isRegister: false,
      showCommentAction: false,
      showCommentActioning: false,
      showProductListAction: false,
      showProductListActioning: false,
    };
  },
  mounted() {
    this.$bus.$once('beforeFinishPage', () => {
      this.$refs.video && this.$refs.video.pausePlayer();
    });
  },
  computed: {
    ...mapState(['articleStates', 'authorStates']),
    articleState() {
      const articleState = this.articleStates[this.data.articleId] || this.data;
      const authorState = this.authorStates[`${this.data.authorUid}-${this.data.authorType}`] || this.data;

      return Object.assign({ ...articleState }, { hasAttention: authorState.hasAttention });
    },
    thumb() {
      return !!this.data.thumb;
    },
    authorData() {
      return {
        authorName: this.data.authorName,
        authorUid: this.data.authorUid,
        authorType: this.data.authorType,
        authorHeadIco: this.data.authorHeadIco,
        authGroupId: this.data.authGroupId,
        hasAttention: this.articleState.hasAttention,
        isAuthor: this.data.isAuthor
      };
    },
    slideData() {
      return {
        blockList: get(this.data, 'blockList', []).filter(block => block.templateKey === 'image'),
        articleId: this.data.articleId,
      };
    },
    productListData() {
      return this.data.productList || [];
    },
    introData() {
      let intro;

      if (this.data.sort === 4) {
        intro = this.data.content;
      } else {
        intro = get(get(this.data, 'blockList', []).filter(block => block.templateKey === 'text'), '[0].contentData', '');
      }
      return {
        authorType: this.data.authorType,
        authorUid: this.data.authorUid,
        articleTitle: this.data.articleTitle,
        intro,
        atUserInfo: this.data.atUserInfo ?? {},
        maxLines: 10
      };
    },
    topicsData() {
      return {
        topicList: this.data.topicList,
        articleType: this.data.articleType
      };
    },
    publishTime() {
      return this.data.publishTime ? dayjs(this.data.publishTime).fromNow() : '';
    },
    lazy() {
      return this.data.lazy;
    }
  },
  methods: {
    onFollowAuthor(follow) {
      this.$emit('on-follow', this.data, follow);
    },
    onPraise() {
      this.$emit('on-praise');
    },
    onChangeSlide({ index }) {
      this.slideIndex = index;
    },

    // onComment({ comment }) {
    //   this.$refs.commentList && this.$refs.commentList.addComment(comment);
    // },
    toCommentList() {
      if (this.$refs.commentList && this.scrollTo) {
        this.scrollTo({ scrollTop: this.$refs.commentList.$el.offsetTop - get(this.$refs, 'header.$el.offsetHeight', 0) });
      }
    },
    onMore() {
      this.$emit('on-show-more');
    },
    onComment() {
      this.showCommentAction = true;
      this.$nextTick(() => {
        if (this.showCommentActioning) {
          return;
        }
        this.showCommentActioning = true;
        this.$refs.comment.init();
        this.$refs.commentAction.show();
        setTimeout(() => {
          this.showCommentActioning = false;
        }, 300);
      });
    },
    onCloseComment() {
      this.$refs.commentAction.hide();
    },
    onActionComment() {
    },

    onProductList() {
      this.showProductListAction = true;
      this.$nextTick(() => {
        if (this.showProductListActioning) {
          return;
        }
        this.showProductListActioning = true;
        this.$refs.productListAction.show();
        setTimeout(() => {
          this.showProductListActioning = false;
        }, 300);
      });
    }
  },
  components: {
    ArticleItemHeader,
    ArticleItemSlide,
    ArticleItemTopics,
    ArticleDetailIntro,
    ArticleDetailCommentList,
  }
};
</script>

<style lang="scss" scoped>
.article-context {
  border-bottom: 1px solid #eee;
}

.article-empty {
  height: 900px;
  color: #ccc;
  font-size: 28px;
  background-color: #f0f0f0;
  display: flex;
  justify-content: center;
  align-items: center;
}

.context-title {
  font-size: 36px;
  color: #222;
  line-height: 56px;
  margin-top: 10px;
  margin-bottom: 16px;
  letter-spacing: 0.68px;
  font-weight: bolder;
  padding: 0 30px;
}

.publish-time {
  font-size: 24px;
  color: #b0b0b0;
  padding: 20px 30px;
  margin-bottom: 40px;
  display: flex;
  align-items: center;
  justify-content: space-between;

  .more-wrap {
    display: flex;
    align-items: center;
    color: #444;

    .iconfont {
      font-size: 44px;
    }
  }
}

.note-video {
  height: 750px;
}

.rec-article-title {
  padding: 14px 0 4px;
  border-top: 1px solid #f0f0f0;
  background-color: #f0f0f0;
}

.product-list-wrapper {
  overflow-y: scroll;
  overflow-x: hidden;
  height: 900px;

  /deep/ .product-item {
    margin: 0 !important;
  }

  /deep/ .product-item-wrapper {
    margin: 0 30px;
  }
}

</style>