Authored by htoooth

Merge remote-tracking branch 'origin/master'

# Conflicts:
#	apps/pages/article/components/article/article.vue
#	apps/store/article/actions.js
... ... @@ -593,6 +593,18 @@ const yoho = {
url = url + 'product/' + skn + '.html';
window.open(url);
}
},
getInput(args, success, fail) {
console.log('get.Input')
if (this.isYohoBuy && window.yohoInterface) {
window.yohoInterface.triggerEvent(success || nullFun, fail || nullFun, {
method: 'get.Input',
arguments: args
});
} else {
// tip(tipInfo);
}
}
};
... ...
<template>
<transition name="action-sheet-fade">
<div class="yoho-popup" :class="actionCls" v-show="isVisible" :style="{'z-index': zIndex}">
<div class="yoho-popup-mask" @click="maskClick"></div>
<div class="yoho-popup-container">
<div class="yoho-popup-content">
<transition name="action-sheet-move">
<div class="detail" v-show="isVisible">
<slot></slot>
</div>
</transition>
<div v-transfer-dom :data-transfer="transfer">
<transition name="action-sheet-fade">
<div class="yoho-popup" :class="actionCls" v-show="isVisible" :style="{'z-index': zIndex}">
<div class="yoho-popup-mask" @click="maskClick"></div>
<div class="yoho-popup-container">
<div class="yoho-popup-content">
<transition name="action-sheet-move">
<div class="detail" v-show="isVisible">
<slot></slot>
</div>
</transition>
</div>
</div>
</div>
</div>
</transition>
</transition>
</div>
</template>
<script>
import { Popup } from 'cube-ui';
export default {
name: 'YohoActionSheet',
props: {
... ... @@ -25,6 +25,7 @@ export default {
type: Boolean,
default: true
},
transfer: Boolean,
zIndex: {
type: Number,
default: 100
... ... @@ -59,9 +60,6 @@ export default {
return [{ 'yoho-action-sheet': this.full }];
}
},
components: {
Popup
},
methods: {
maskClick() {
this.maskClosable && this.cancel();
... ... @@ -92,7 +90,7 @@ export default {
.action-sheet-fade-enter-active,
.action-sheet-fade-leave-active {
transition: all 0.3s ease-in-out;
transition: all 0.2s ease-in-out;
}
.action-sheet-move-enter,
... ... @@ -102,7 +100,7 @@ export default {
.action-sheet-move-enter-active,
.action-sheet-move-leave-active {
transition: all 0.3s ease-in-out;
transition: all 0.2s ease-in-out;
}
.yoho-popup {
... ... @@ -119,6 +117,7 @@ export default {
.yoho-popup-mask,
.yoho-popup-container {
background-color: #fff;
position: absolute;
width: 100%;
height: 100%;
... ... @@ -133,6 +132,8 @@ export default {
.detail {
position: relative;
width: 100%;
height: 100%;
}
</style>
... ...
... ... @@ -13,7 +13,9 @@
</Scroll>
</div>
<div class="comment-footer">
<div class="comment-input" @click="onComment">参与评论</div>
<CommentPlaceholder class="comment-input">
参与评论
</CommentPlaceholder>
</div>
</div>
</template>
... ... @@ -21,8 +23,8 @@
<script>
import CommentItem from './comment-item.vue';
import {Scroll} from 'cube-ui';
import {createNamespacedHelpers} from 'vuex';
import {get} from 'lodash';
import {createNamespacedHelpers} from 'vuex';
const {mapActions} = createNamespacedHelpers('comment');
export default {
... ... @@ -46,11 +48,19 @@ export default {
noMore: '- 已经到底了 -'
}
}
}
},
show: false
};
},
watch: {
destId() {
this.init();
}
},
mounted() {
this.fetchComments();
setTimeout(() => {
this.fetchComments();
}, 200);
},
methods: {
...mapActions(['fetchCommentList', 'fetchReplayList', 'postComment']),
... ... @@ -63,15 +73,15 @@ export default {
let dirty = true;
if (result.code === 200) {
const appendComments = get(result, 'data.commentInfos', []);
const comments = get(result, 'data.commentInfos', []);
if (refresh) {
this.commentList = appendComments;
this.commentList = comments;
} else {
this.commentList = this.commentList.concat(appendComments);
this.commentList = this.commentList.concat(comments);
}
if (appendComments.length) {
if (comments.length) {
this.page++;
} else {
dirty = false;
... ... @@ -87,7 +97,6 @@ export default {
time: 1000
}).show();
}
this.$refs.scroll.forceUpdate(dirty);
return result;
},
... ... @@ -103,7 +112,7 @@ export default {
});
if (result.code === 200) {
this.onRefresh();
this.init();
} else {
this.$createToast({
txt: result.message || '服务器开小差了',
... ... @@ -112,7 +121,7 @@ export default {
}).show();
}
},
async onRefresh() {
async init() {
this.page = 1;
await this.fetchComments(true);
this.$refs.scroll.forceUpdate(true);
... ...
export default {
name: 'CommentPlaceholder',
props: {
tag: String,
destId: Number,
addType: Number,
columnType: {
type: Number,
default: 1001
},
placeholder: String
},
methods: {
openComentInput() {
this.$yoho.getInput({
hint: '你好',
success: (content) => {
console.log(content)
},
fail: (e) => {
console.log('fail', e)
}
});
}
},
render(h) {
return h(this.tag || 'div', {
on: {
click: () => {
this.openComentInput();
}
}
}, this.$slots.default);
}
};
... ...
<template>
<Layout>
<LayoutHeader :back="!popup" theme="white" slot='header'>
{{headerText}}
<template v-slot:opts v-if="popup">
<i class="iconfont icon-close icon" @click="onClose"></i>
</template>
</LayoutHeader>
<CommentList :dest-id="destId" :column-type="1001" @on-page-change="onPageChange"></CommentList>
</Layout>
</template>
<script>
import CommentList from './comment-list';
export default {
name: 'Comment',
props: {
destId: Number,
popup: {
type: Boolean,
default: false
}
},
data() {
return {
size: 0
};
},
computed: {
headerText() {
return this.size ? `${this.size}条评论` : '';
}
},
methods: {
onPageChange({size}) {
this.size = size;
},
onClose() {
this.$emit('on-close');
}
},
components: {CommentList}
};
</script>
... ...
import CommentList from './comment-list';
import Comment from './comment';
import CommentPlaceholder from './comment-placeholder';
export default [
CommentList,
Comment,
CommentPlaceholder
];
... ...
<template>
<img v-lazy="currentSrc" :alt="alt" v-if="lazy">
<img :src="currentSrc" :alt="alt" v-else>
<img v-lazy="currentSrc" :alt="alt" v-if="currentLazy">
<img :src="currentSrc" :alt="alt" v-else lazy="" data-src="">
</template>
<script>
... ... @@ -22,12 +22,16 @@ export default {
},
data() {
return {
refresh: false
refresh: false,
currentLazy: this.lazy
};
},
watch: {
src() {
this.lazy = false;
this.currentLazy = false;
},
lazy(val) {
this.currentLazy = val;
}
},
computed: {
... ...
<template>
<div class="layout-header" :class="{[`theme-${theme}`]: theme}">
<div class="back flex hover-opacity" @click="onBack">
<slot name="back">
<slot name="back" v-if="back">
<i class="iconfont icon-left"></i>
</slot>
</div>
... ... @@ -25,6 +25,10 @@ export default {
title: String,
theme: String,
fixed: Boolean,
back: {
type: Boolean,
default: true
},
transparentSeek: Number,
opacity: {
type: Number,
... ... @@ -53,7 +57,7 @@ export default {
},
methods: {
onBack() {
if (this.yoho.ssrLoad) {
if (this.yoho.homePage) {
this.$yoho.finishPage({});
} else {
this.$router.go(-1);
... ...
... ... @@ -34,6 +34,11 @@ export default {
favorite: this.product.favorite
};
},
watch: {
'product.favorite'(val) {
this.favorite = val;
}
},
computed: {
favClass() {
return {'btn-is-fav': this.favorite, loading: this.posting};
... ...
... ... @@ -76,9 +76,7 @@
},
created() {
forEach(defaultOption, (value, key) => {
if (!this.viewOption.hasOwnProperty(key)) {
this.viewOption[key] = this.option.hasOwnProperty(key) ? this.option[key] : defaultOption[key];
}
this.viewOption[key] = this.option.hasOwnProperty(key) ? this.option[key] : defaultOption[key];
});
this.viewOption = {...this.viewOption};
},
... ...
import Vue from 'vue';
import focus from './focus';
import TransferDom from './transfer-dom';
import Tap from './tap';
Vue.directive('focus', focus);
Vue.directive('TransferDom', TransferDom);
Vue.directive('Tap', Tap);
... ...
... ... @@ -3,6 +3,7 @@ import createReport from 'report-error';
import {
SET_ENV,
ROUTE_CHANGE
} from 'store/yoho/types';
... ... @@ -18,6 +19,9 @@ export default context => {
router.onReady(() => {
const matched = router.getMatchedComponents();
store.commit(ROUTE_CHANGE, {to: router.currentRoute});
if (matched.some(m => !m)) {
reportError(new Error('导航组件为空'));
router.push({name: 'error.500'});
... ...
<template>
<Layout class="article">
<LayoutHeader theme="white" slot='header'>
{{headerText}}
</LayoutHeader>
<CommentList :dest-id="destId" :column-type="1001" @on-page-change="onPageChange"></CommentList>
</Layout>
<Comment :dest-id="destId"></Comment>
</template>
<script>
export default {
name: 'ArticleComment',
data() {
... ... @@ -18,19 +14,7 @@ export default {
computed: {
destId() {
return parseInt(this.$route.params.articleId, 10);
},
headerText() {
return this.size ? `${this.size}条评论` : '';
}
},
methods: {
onPageChange({size}) {
this.size = size;
}
}
};
</script>
<style>
</style>
... ...
... ... @@ -31,12 +31,7 @@ export default {
methods: {
...mapActions(['postComment']),
onGoComment() {
this.$router.push({
name: 'article.comment',
params: {
articleId: this.data.articleId
}
});
this.$emit('on-comment');
},
onComment() {
this.postComment({
... ...
... ... @@ -18,9 +18,9 @@
<WidgetShare></WidgetShare>
</div>
<div class="opts">
<WidgetFav :num="data.favoriteCount" :article-id="data.articleId" :option="favoriteOption"></WidgetFav>
<WidgetLike :num="data.praiseCount" :article-id="data.articleId" :option="praiseOption"></WidgetLike>
<WidgetComment :num="data.commentCount"></WidgetComment>
<WidgetFav :num="data.praiseCount" :article-id="data.articleId" :option="praiseOption"></WidgetFav>
<WidgetLike :num="data.favoriteCount" :article-id="data.articleId" :option="favoriteOption"></WidgetLike>
<WidgetComment :num="data.commentCount" @click.native="onComment"></WidgetComment>
</div>
</div>
</div>
... ... @@ -117,6 +117,9 @@ export default {
},
resizeScroll() {
this.$emit('on-resize');
},
onComment() {
this.$emit('on-comment');
}
}
};
... ...
... ... @@ -3,8 +3,8 @@
<ArticleItemHeader :data="headerData" :lazy="lazy" @on-follow="onFollow"></ArticleItemHeader>
<ArticleItemSlide :data="slideData" :lazy="lazy"></ArticleItemSlide>
<ProductGroup v-if="productListData.length" :data="productListData" :lazy="lazy"></ProductGroup>
<ArticleItemIntro :data="introData" @on-resize="onResize" @on-resizeing="onResizeing" @on-expand="onExpand"></ArticleItemIntro>
<ArticleItemComment :data="commentData"></ArticleItemComment>
<ArticleItemIntro :data="introData" @on-resize="onResize" @on-resizeing="onResizeing" @on-expand="onExpand" @on-comment="onComment"></ArticleItemIntro>
<ArticleItemComment :data="commentData" @on-comment="onComment"></ArticleItemComment>
<div class="line"></div>
</div>
</template>
... ... @@ -83,6 +83,9 @@ export default {
},
onExpand() {
this.$emit('on-expand', {articleId: this.data.relateId, grassId: this.data.articleId});
},
onComment() {
this.$emit('on-comment', this.data);
}
},
components: {ArticleItemHeader, ArticleItemSlide, ArticleItemIntro, ArticleItemComment}
... ...
... ... @@ -18,13 +18,17 @@
@on-resize="onResize(data)"
@on-resizeing="onResizeing(data)"
@on-follow="follow => onFollow(data, follow)"
@on-expand="onExpand"></ArticleItem>
@on-expand="onExpand"
@on-comment="onComment"></ArticleItem>
<div :id="`ph${data.index}`"></div>
</template>
</LayoutRecycleList>
<slot name="thumb" v-else></slot>
<ArticleActionSheet ref="actionSheet"></ArticleActionSheet>
<ArticleActionSheet v-if="showArticleDetailAction" ref="actionSheet"></ArticleActionSheet>
<YohoActionSheet transfer v-if="showCommentAction" ref="commentAction" :full="true">
<Comment :destId="articleId" :popup="true" @on-close="onClose"></Comment>
</YohoActionSheet>
</Layout>
</template>
... ... @@ -46,6 +50,9 @@ export default {
},
data() {
return {
articleId: 0,
showCommentAction: false,
showArticleDetailAction: false,
shareData: {},
inx: 0,
scrollTop: 0,
... ... @@ -67,6 +74,16 @@ export default {
}
},
methods: {
onComment({articleId}) {
this.articleId = articleId;
this.showCommentAction = true;
this.$nextTick(() => {
this.$refs.commentAction.show();
});
},
onClose() {
this.$refs.commentAction.hide();
},
onScroll({item, scrollTop}) {
this.scrollTop = scrollTop;
if (scrollTop === 0) {
... ... @@ -132,16 +149,15 @@ export default {
toast.show();
this.$refs.actionSheet.show(params).then(() => {
toast.hide();
}).catch(() => {
toast.hide();
this.$createToast && this.$createToast({
txt: '服务器开小差了',
type: 'warn',
time: 1000
}).show();
this.showArticleDetailAction = true;
this.$nextTick(() => {
this.$refs.actionSheet.show(params).then(() => {
toast.hide();
this.$createToast && this.$createToast({
txt: '服务器开小差了',
type: 'warn',
time: 1000
}).show();
});
}
},
... ...
... ... @@ -10,8 +10,6 @@
@on-comment-click="onCommentClick"
@on-close="onClose">
</ArticleFooter>
<CommentActionSheet ref="actionSheet"></CommentActionSheet>
</div>
</template>
... ... @@ -20,7 +18,6 @@
import ArticleBar from './article-bar';
import ArticleFooter from './article-footer';
import ArticleBody from './article-body';
import CommentActionSheet from './comment-action-sheet';
import { createNamespacedHelpers } from 'vuex';
const { mapActions, mapState, mapMutations } = createNamespacedHelpers('article');
... ... @@ -31,7 +28,6 @@ export default {
ArticleBar,
ArticleBody,
ArticleFooter,
CommentActionSheet
},
data() {
return {
... ... @@ -43,8 +39,12 @@ export default {
},
methods: {
onCommentClick() {
this.$refs.actionSheet.destId = this.grassId;
this.$refs.actionSheet.click();
this.$router.push({
name: 'article.comment',
params: {
articleId: this.grassId
}
});
},
...mapActions(['getDetail']),
...mapMutations({
... ...
... ... @@ -9,9 +9,6 @@ export default [{
path: '/topic/:labelId',
name: 'topic',
component: () => import(/* webpackChunkName: "article" */ './topic'),
meta: {
keepAlive: true
}
}, {
path: '/article/:articleId/comment',
name: 'article.comment',
... ...
... ... @@ -25,9 +25,8 @@ export default {
}
return result;
},
async fetchArticleProductFavs({ commit }, { articles }) {
const products = [],
ufoProducts = [];
async fetchArticleProductFavs({commit}, {articles}) {
const products = [], ufoProducts = [];
articles.forEach(article => {
get(article, 'productList', []).forEach(product => {
... ... @@ -49,30 +48,24 @@ export default {
if (!result.data) {
result.data = [];
}
commit(Types.FETCH_ARTICLE_PRODUCT_SUCCESS, {
articles,
favs: result.data,
articleProductType: 1
});
commit(Types.FETCH_ARTICLE_PRODUCT_SUCCESS, {articles, favs: result.data, articleProductType: 1});
}
}
if (ufoProducts.length) {
const result = await this.$api.get('/api/ufo/user/isFavoriteBatch', {
productIds: ufoProducts.join(',')
productIds: ufoProducts.join(','),
});
commit(Types.FETCH_ARTICLE_PRODUCT_SUCCESS, {
articles,
favs: result.data,
articleProductType: 2
});
if (result.code === 200) {
if (!result.data) {
result.data = [];
}
commit(Types.FETCH_ARTICLE_PRODUCT_SUCCESS, {articles, favs: result.data, articleProductType: 2});
}
}
},
async fetchArticleListByTopic(
{ commit, state },
{ labelId, limit = 5, page = 1 }
) {
commit(Types.FETCH_ARTICLE_TOPIC_REQUEST, { page });
async fetchArticleListByTopic({commit, state}, {labelId, limit = 5, page = 1}) {
commit(Types.FETCH_ARTICLE_TOPIC_REQUEST, {page});
const result = await this.$api.get('/api/grass/labelRealtedArticleDetail', {
labelId,
limit,
... ... @@ -101,7 +94,7 @@ export default {
getRecommendProducts: [],
footer: {},
zanBar: {},
tagBar: []
tagBar: [],
};
const data = await this.$api.get('/api/guang/article/detail', {
... ...
... ... @@ -26,7 +26,7 @@ export default function() {
},
historys: [],
direction: 'forword',
ssrLoad: true, // 是否是ssr直出的页面
homePage: true
},
mutations: {
[Types.SET_ENV](state, {context}) {
... ... @@ -39,14 +39,7 @@ export default function() {
[Types.SET_TITLE](state, {title}) {
state.context.title = title;
},
[Types.ROUTE_CHANGE](state, {to, from}) {
state.ssrLoad = false;
if (!state.historys.length) {
state.historys.push({
name: from.name,
path: from.fullPath
});
}
[Types.ROUTE_CHANGE](state, {to}) {
const routeIndex = state.historys.findIndex(route => route.path === to.fullPath);
if (routeIndex >= 0) {
... ... @@ -59,6 +52,7 @@ export default function() {
});
state.direction = 'forword';
}
state.homePage = state.historys.length <= 1;
},
[Types.SET_NEED_LOGIN](state, {needLogin}) {
state.context.needLogin = needLogin;
... ...