topic.vue 11.1 KB
<template>
  <div>
    <Layout class="article">
      <TopicHeader ref="header" :title="topicTitle" :step="headerAnimateStep" :data="topicInfo" @on-follow="onFollowTopic"></TopicHeader>

      <RecycleScrollReveal v-if="topicInfo.viewModel == 2" :size="20" :thumbs="thumbs" ref="scroll" @scroll="onScroll" :offset="2000" :on-fetch="onFetch"
      @on-inited="onInited">
        <template v-slot:eternalTop>
          <TopicBanner ref="topicHead" :data="topicInfo" @on-follow="onFollowTopic"></TopicBanner>
        </template>
        <template class="article-item" #item="{ data }">
          <ArticleItem2
            type="topic"
            :index="data.index"
            :data="data.data"
            :width="colWidthForTwo"
            :share="share"
            :article-id="data.data.articleId"
            :pos-id="posId">
            <template v-if="data.data.dataType == 2">
              <ArticleResource :data="data.data"></ArticleResource>
            </template>
          </ArticleItem2>
        </template>
      </RecycleScrollReveal>

      <LayoutRecycleList v-if="topicInfo.viewModel == 1" :size="10" :thumbs="thumbs" ref="scroll" @scroll="onScroll" :offset="2000" :on-fetch="onFetch"
      @on-inited="onInited">
        <template class="article-item" #item="{ data }">
          <TopicBanner v-if="data.data.topicHead" ref="topicHead" :data="topicInfo" @on-follow="onFollowTopic"></TopicBanner>
          <ArticleItem
            v-else
            type="topic"
            :index="data.index"
            :data="data.data"
            :share="share"
            :article-id="data.data.articleId"
            :pos-id="posId"
            @on-follow="follow => onFollow(data.data, follow)"
            @on-resize="onResize"
            @on-unlock-height="onUnlockHeight"
            @on-show-guang="onShowGuang"
            @on-show-comment="onShowComment"
            @on-show-more="onShowMore">
            <template v-if="data.data.dataType == 2">
              <ArticleResource :data="data.data"></ArticleResource>
            </template>
          </ArticleItem>
        </template>
      </LayoutRecycleList>

      <a v-if="publishUrl" class="publish-btn" :href="publishUrl">
        <span class="avatar-block">
          <WidgetAvatar class="avatar" :width="70" :height="70"></WidgetAvatar>
        </span>
        立即参与
      </a>

    </Layout>
    <ArticleActionSheet v-if="showArticleDetailAction" ref="actionSheet"></ArticleActionSheet>
    <YohoActionSheet transfer v-if="showCommentAction" ref="commentAction" :full="true">
      <Comment ref="comment"
        :destId="articleId"
        :popup="true"
        :article-id="articleId"
        :pos-id="posId"
        @on-close="onClose"
        @on-comment="onActionComment"></Comment>
    </YohoActionSheet>
    <MoreActionSheet transfer ref="moreAction" @on-follow="onFollow" @on-delete="onDelete"></MoreActionSheet>
  </div>
</template>

<script>
import {throttle, get} from 'lodash';
import YAS from 'utils/yas-constants';
import ArticleItem from './components/article/article-item';
import ArticleItem2 from './components/article/article-item2';
import ArticleActionSheet from './components/detail/article-action-sheet';
import MoreActionSheet from './components/detail/more-action-sheet';
import TopicHeader from './components/topic/header';
import TopicBanner from './components/topic/banner';
import {createNamespacedHelpers} from 'vuex';
const {mapState, mapMutations, mapActions} = createNamespacedHelpers('article');

const throttleTime = 40;

export default {
  name: 'TopicPage',
  created() {
    this.topicName = this.$route.params.topicName;
  },
  activated() {
    if (this.scrollTop > 0) {
      this.$refs.scroll.$el.scrollTop = this.scrollTop;
    }

    if (+this.$route.params.topicId !== this.topicId) {
      this.topicId = +this.$route.params.topicId;
      this.topicName = this.$route.params.topicName;
      this.reload = true;
      this.init();
    }
  },
  beforeRouteUpdate(to, from, next) {
    if (+this.$route.params.topicId !== +to.params.topicId) {
      this.topicId = +to.params.topicId;
      this.topicName = to.params.topicName;
      this.init();
    }
    next();
  },
  mounted() {
    this.scrollEvent = throttle(this.onDounceScroll.bind(this), throttleTime);
    this.reportShow = this.startReportShow();
    this.colWidthForTwo = Math.floor(this.$el.offsetWidth / 2);
  },
  data() {
    return {
      share: false,
      thumbs: [],
      posId: YAS.scene.topicList,
      topicId: 0,
      topicName: '',
      headerAnimateStep: 0,
      articleId: 0,
      articleIndex: -1,
      showCommentAction: false,
      showCommentActioning: false,
      showArticleDetailAction: false,
      showMoreAction: true,
      scrollTop: 0,
      currentId: 0,
      colWidthForTwo: 0,
    };
  },
  computed: {
    ...mapState(['topicInfo']),
    publishUrl() {
      return this.topicId ? `?openby:yohobuy={"action":"go.grasspublish","params":{"topicId":"${this.topicId}","topicName":"${this.topicName}"}}` : '';
    },
    topicTitle() {
      return this.topicName || this.topicInfo.topicName || '';
    },
    headerBgOpacity() {
      return this.headerAnimateStep / 100;
    }
  },
  methods: {
    ...mapActions(['fetchTopicSimpleInfo', 'fetchTopicRelatedArticles', 'fetchArticleProductFavs']),
    ...mapMutations(['ASYNC_ARTICLE_COMMENT', 'CHANGE_AUTHOR_FOLLOW', 'CHANGE_TOPIC_FOLLOW']),
    onShowComment({articleId, index}) {
      this.articleId = articleId;
      this.articleIndex = index;
      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);
      });
    },
    onShowMore({article, index}) {
      this.$refs.moreAction.show(article, this.userUid, index);
    },
    onDelete(index) {
      this.$refs.scroll.delete(index);
    },
    onPageReady({success}) {
      if (success && this.showCommentAction) {
        this.$refs.commentAction.show();
        setTimeout(() => {
          this.showCommentActioning = false;
        }, 300);
      } else {
        this.showCommentActioning = false;
      }
    },
    onUnlockHeight(params) {
      this.$refs.scroll.unlockHight(params);
    },
    onClose() {
      this.$refs.commentAction.hide();
    },
    onActionComment() {
      this.ASYNC_ARTICLE_COMMENT({articleId: this.articleId, type: this.type});
      this.onResize(this.articleIndex);
    },
    onScroll(params) {
      this.scrollEvent(params);

      setTimeout(() => {
        this.scrollEvent(params);
      }, throttleTime)
    },
    onDounceScroll({item, scrollTop, startIndex}) {
      if (this.scrollTop === scrollTop) {
        return;
      }

      this.scrollTop = scrollTop || 0;
      this._headerHeight = this._headerHeight || this.$refs.header.$el.offsetHeight;
      this._topicHeaderHeight = this._topicHeaderHeight || this.$refs.topicHead.$el.offsetHeight;

      let step = Math.round((scrollTop - 10) / (this._topicHeaderHeight - this._headerHeight) * 100);

      this.headerAnimateStep = Math.max(Math.min(step, 100), 0);

      if (+get(item, 'data.dataType') === 1) {
        if (this._currentId !== item.data.articleId) {
          this._currentId = item.data.articleId;
          this.reportShow(--startIndex, item);
        }
      }
    },
    init() {
      this.page = 1;
      this.fetchTopicSimpleInfo({topicId: this.topicId});
      if (this.$refs.scroll) {
        this.$refs.scroll.$el.scrollTop = 0;
        this.$refs.scroll.init();
      }
    },
    async onFetch() {
      const topicId = parseInt(this.topicId, 10);

      if (!topicId) {
        return;
      }

      this.page = this.page || 1;

      const result = await this.fetchTopicRelatedArticles({
        topicId,
        page: this.page
      });

      let list = [];

      if (result.code === 200) {
        this.page++;
        list = get(result, 'data.detailList', []);

        if (list.length) {
          this.$sdk.getUser().then(user => {
            if (user && user.uid) {
              this.fetchArticleProductFavs({
                articles: list
              });
            }
          });
        }
      } else {
        this.$createToast && this.$createToast({
          txt: result.message || '服务器开小差了',
          type: 'warn',
          time: 1000
        }).show();
      }

      return new Promise(resolve => {
        if (this.topicInfo.viewModel === 1 && this.page <= 2) {
          list = [{topicHead: true}, ...list];
        }

        setTimeout(() => {
          resolve(list.length ? list : false);
        }, this.reload ? 300 : 0);
        this.reload = false;
      });
    },
    onInited(item) {
      if (item) {
        this.reportShow(0, item);
      }
    },
    onFollow(data, follow) {
      this.CHANGE_AUTHOR_FOLLOW({authorUid: data.authorUid, follow, type: this.type});
    },
    onFollowTopic(follow) {
      this.CHANGE_TOPIC_FOLLOW({topicId: this.topicId, follow});
    },
    onResize(index) {
      this.$nextTick(() => {
        this.$refs.scroll.resize(index);
      });
    },
    onShowGuang(params) {
      this.showArticleDetailAction = true;
      this.$nextTick(() => {
        this.$refs.actionSheet.show(params);
      });
    },
    startReportShow() {
      let preview = null;
      let name = this.$yoho.isiOS ? 'iFP_ArticleList' : 'aFP_ArticleList';

      return (index, item) => {
        if (preview === item.data.articleId) {
          return;
        }

        preview = item.data.articleId;

        this.$store.dispatch('reportYas', {
          params: {
            appop: YAS.eventName.show,
            param: {
              DATA: [{
                P_NAME: name,
                P_PARAM: preview,
                I_INDEX: index,
                ARTICLE_ID: preview,
                POS_ID: this.posId
              }, ...(item.data.productList || []).map(p => {
                return {
                  P_NAME: name,
                  P_PARAM: preview,
                  I_INDEX: index,
                  PRD_SKN: p.productSkn,
                  POS_ID: this.posId
                };
              })],
            }
          }
        });
      };
    }
  },
  components: {
    ArticleItem,
    ArticleItem2,
    ArticleActionSheet,
    MoreActionSheet,
    TopicHeader,
    TopicBanner
  }
};
</script>

<style scoped>
  /deep/ .recycle-scroll-reveal-main {
    background-color: #f7f7f7;

    .scroll-reveal-list {
      padding: 5px;
    }
  }

  /deep/ .att-click-wrap {
    opacity: 0;
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    z-index: 1;
  }

  .publish-btn {
    width: 260px;
    height: 80px;
    border-radius: 42px;
    font-size: 30px;
    color: #fff;
    background: #D0021B;
    position: absolute;
    bottom: 100px;
    left: calc(50% - 130px);
    z-index: 1;
    display: flex;
    align-items: center;

    .avatar-block {
      width: 52px;
      height: 52px;
      margin: 14px 30px 14px 14px;
      border-radius: 50%;
      overflow: hidden;
    }

    .avatar {
      display: block;
      width: 100%;
      height: 100%;
    }
  }

</style>