Authored by 陈峰

commit

... ... @@ -15,6 +15,7 @@
],
"rules": {
"camelcase": "off",
"max-len": "off"
"max-len": "off",
"new-cap": "off"
}
}
... ...
<template>
<button class="btn-follow hover-opacity" v-if="!followed">关注</button>
<button class="btn-follow followed hover-opacity" v-else>已关注</button>
<button class="btn-follow hover-opacity" :class="followClass" @click="onFollow">{{followText}}</button>
</template>
<script>
import {createNamespacedHelpers} from 'vuex';
const {mapActions} = createNamespacedHelpers('user');
export default {
name: 'WidgetFollow',
props: {
authorUid: Number,
followed: Boolean
follow: Boolean
},
data() {
return {
loading: false,
followStatus: this.follow
};
},
watch: {
follow(val) {
this.followStatus = val;
}
},
computed: {
followClass() {
return {
loading: this.loading,
follow: this.followStatus
};
},
followText() {
return this.followStatus ? '已关注' : '关注';
}
},
methods: {
...mapActions(['followUser']),
async onFollow() {
if (this.loading) {
return;
}
this.loading = true;
const result = await this.followUser({followUid: this.authorUid, status: this.followStatus ? 1 : 0});
this.loading = false;
if (result.code === 200) {
this.followStatus = !this.followStatus;
this.$emit('on-follow', this.followStatus);
} else {
this.$createToast && this.$createToast({
txt: result.message || '服务器开小差了',
type: 'warn',
time: 1000
}).show();
}
}
}
};
</script>
... ... @@ -26,7 +72,7 @@ export default {
align-items: center;
justify-content: center;
&.followed {
&.follow {
border: solid 1px #4a4a4a;
background-color: #fff;
color: #000;
... ...
... ... @@ -21,24 +21,23 @@ export default {
};
},
serverPrefetch() {
console.log('serverPrefetch')
return this.onFetch();
},
computed: {
...mapState(['articleCurrentList']),
...mapState(['articleList']),
currentList() {
if (this.articleCurrentList.length > 2) {
return this.articleCurrentList.slice(0, 2);
if (this.articleList.length > 2) {
return this.articleList.slice(0, 2);
}
return this.articleCurrentList;
return this.articleList;
}
},
methods: {
...mapActions(['fetchArticleList']),
async onFetch() {
if (this.page === 1 && this.articleCurrentList.length) {
if (this.page === 1 && this.articleList.length) {
this.page++;
return this.articleCurrentList;
return this.articleList;
}
const articleId = parseInt(this.$route.params.id, 10);
... ...
... ... @@ -5,7 +5,7 @@
<span class="name">{{data.authorName}}</span>
</div>
<div class="opts">
<WidgetFollow :article-id="data.authorUid" :followed="data.hasAttention === 'Y'"></WidgetFollow>
<WidgetFollow :author-uid="data.authorUid" :follow="data.hasAttention === 'Y'" @on-follow="onFollow"></WidgetFollow>
<i class="iconfont icon-more1" @click="onMore"></i>
</div>
</div>
... ... @@ -40,6 +40,9 @@ export default {
}).show();
}
}).show();
},
onFollow(follow) {
this.$emit('on-follow', follow);
}
}
};
... ...
<template>
<div class="article-item">
<ArticleItemHeader :data="headerData" :lazy="lazy"></ArticleItemHeader>
<ArticleItemHeader :data="headerData" :lazy="lazy" @on-follow="onFollow"></ArticleItemHeader>
<ArticleItemSlide :data="slideData" :lazy="lazy"></ArticleItemSlide>
<ProductGroup :data="productListData" :lazy="lazy"></ProductGroup>
<ArticleItemIntro :data="introData" @on-resize="onResize" @on-resizeing="onResizeing"></ArticleItemIntro>
... ... @@ -73,6 +73,9 @@ export default {
},
onResizeing() {
this.$emit('on-resizeing');
},
onFollow(follow) {
this.$emit('on-follow', follow);
}
},
components: {ArticleItemHeader, ArticleItemSlide, ArticleItemIntro, ArticleItemComment}
... ...
... ... @@ -6,12 +6,17 @@
<span class="user-name">{{currentAuthor.authorName}}</span>
</template>
<template v-if="showHeader" v-slot:opts>
<WidgetFollow :article-id="currentAuthor.authorUid" :followed="currentAuthor.hasAttention === 'Y'"></WidgetFollow>
<WidgetFollow class="widget-follow" :author-uid="currentAuthor.authorUid" :follow="currentAuthor.hasAttention === 'Y'" @on-follow="follow => onFollow(currentAuthor, follow)"></WidgetFollow>
</template>
</LayoutHeader>
<LayoutScroll v-if="isMounted" ref="scroll" @scroll="onScroll" :offset="1000" :on-fetch="onFetch">
<template class="article-item" v-slot:item="{ data }">
<ArticleItem :id="`item${data.index}`" :data="data" :data-id="data.index" @on-resize="onResize(data)" @on-resizeing="onResizeing(data)"></ArticleItem>
<ArticleItem
:id="`item${data.index}`"
:data="data" :data-id="data.index"
@on-resize="onResize(data)"
@on-resizeing="onResizeing(data)"
@on-follow="follow => onFollow(data, follow)"></ArticleItem>
<div :id="`ph${data.index}`"></div>
</template>
</LayoutScroll>
... ... @@ -21,6 +26,8 @@
<script>
import ArticleItem from './article-item';
import {createNamespacedHelpers} from 'vuex';
const {mapMutations} = createNamespacedHelpers('article');
export default {
name: 'Article',
... ... @@ -59,6 +66,7 @@ export default {
}
},
methods: {
...mapMutations(['CHANGE_AUTHOR_FOLLOW']),
onScroll({item, scrollTop}) {
this.scrollTop = scrollTop;
if (scrollTop === 0) {
... ... @@ -108,6 +116,12 @@ export default {
$phItem.style.zIndex = 999;
$phItem.status = 1;
},
onFollow(data, follow) {
this.CHANGE_AUTHOR_FOLLOW({authorUid: data.authorUid, follow});
if (data.authorUid === this.currentAuthor.authorUid) {
this.currentAuthor.hasAttention = follow ? 'Y' : 'N';
}
}
},
components: {
ArticleItem
... ... @@ -125,24 +139,8 @@ export default {
height: 52px;
}
.btn-follow {
width: 120px;
height: 50px;
padding: 0;
font-size: 26px;
border-radius: 3PX;
background-color: #222;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
.widget-follow {
margin-right: 30px;
&.followed {
border: solid 1px #4a4a4a;
background-color: #fff;
color: #222;
}
}
.user-name {
... ...
... ... @@ -684,6 +684,10 @@ img[lazy=loaded] {
&:active {
opacity: 0.8;
}
&.loading {
opacity: 0.8;
}
}
button {
... ...
... ... @@ -14,12 +14,9 @@ export default {
if (!result.data.detailList) {
result.data.detailList = [];
}
result.data.detailList = result.data.detailList.map((item, inx) => {
item.index = (page - 1) * limit + inx;
return item;
});
commit(Types.FETCH_ARTICLE_DETAIL_SUCCESS, {
data: result.data.detailList,
page
});
} else {
commit(Types.FETCH_ARTICLE_DETAIL_FAILD);
... ...
... ... @@ -6,7 +6,7 @@ export default function() {
namespaced: true,
state: {
fetchArticleList: false,
articleCurrentList: [],
articleList: [],
articleDetail: null,
},
actions,
... ...
... ... @@ -4,15 +4,28 @@ export default {
[Types.FETCH_ARTICLE_DETAIL_REQUEST](state) {
state.fetchArticleList = true;
},
[Types.FETCH_ARTICLE_DETAIL_SUCCESS](state, {data}) {
[Types.FETCH_ARTICLE_DETAIL_SUCCESS](state, {data, page}) {
state.fetchArticleList = false;
state.articleCurrentList = data;
if (page === 1) {
state.articleList = [];
}
state.articleList = state.articleList.concat(data);
state.articleList.forEach((item, index) => {
item.index = index;
});
},
[Types.FETCH_ARTICLE_DETAIL_FAILD](state) {
state.fetchArticleList = false;
},
[Types.FETCH_GUANG_REQUEST](state, data) {
state.articleDetail = data;
},
[Types.CHANGE_AUTHOR_FOLLOW](state, {authorUid, follow}) {
state.articleList.forEach(article => {
if (article.authorUid === authorUid) {
article.hasAttention = follow ? 'Y' : 'N';
}
});
}
};
... ...
export const FETCH_ARTICLE_DETAIL_REQUEST = 'FETCH_ARTICLE_DETAIL_REQUEST';
export const FETCH_ARTICLE_DETAIL_FAILD = 'FETCH_ARTICLE_DETAIL_FAILD';
export const FETCH_ARTICLE_DETAIL_SUCCESS = 'FETCH_ARTICLE_DETAIL_SUCCESS';
export const FETCH_GUANG_REQUEST = 'FETCH_GUANG_REQUEST';
export const FETCH_GUANG_FAILED = 'FETCH_GUANG_FAILED';
export const FETCH_GUANG_SUCCESS = 'FETCH_GUANG_SUCCESS';
export const CHANGE_AUTHOR_FOLLOW = 'CHANGE_AUTHOR_FOLLOW';
... ...
... ... @@ -3,6 +3,7 @@ import Vuex from 'vuex';
import {createApi} from 'create-api';
import storeYoho from './yoho';
import storeArticle from './article';
import storeUser from './user';
import plugin from './plugin';
Vue.use(Vuex);
... ... @@ -12,7 +13,8 @@ export function createStore(context) {
namespaced: true,
modules: {
yoho: storeYoho(),
article: storeArticle()
article: storeArticle(),
user: storeUser()
},
strict: process.env.NODE_ENV !== 'production',
plugins: [plugin]
... ...
export default {
async followUser(actions, {followUid, status}) {
const result = await this.$api.get('/api/grass/updateAttention', {
followUid,
status,
attentionType: 1
});
return result;
},
async followTopic(actions, {topicId, status}) {
const result = await this.$api.get('/api/grass/updateAttention', {
topicId,
status,
attentionType: 0
});
return result;
},
};
... ...
import actions from './actions';
import mutations from './mutations';
export default function() {
return {
namespaced: true,
state: {
},
actions,
mutations
};
}
... ...
import * as Types from './types';
export default {
};
... ...
export const FETCH_ARTICLE_DETAIL_REQUEST = 'FETCH_ARTICLE_DETAIL_REQUEST';
export const FETCH_ARTICLE_DETAIL_FAILD = 'FETCH_ARTICLE_DETAIL_FAILD';
export const FETCH_ARTICLE_DETAIL_SUCCESS = 'FETCH_ARTICLE_DETAIL_SUCCESS';
\ No newline at end of file
... ...
... ... @@ -8,11 +8,19 @@ module.exports = {
params: {
page: {type: Number, require: false},
limit: {type: Number, require: false},
uid: {type: Number, require: false},
articleId: {type: Number},
columnType: {type: Number}
}
},
'/api/grass/updateAttention': {
api: 'app.grass.updateAttention',
params: {
topicId: {type: Number, require: false},
followUid: {type: Number, require: false},
status: {type: Number},
attentionType: {type: Number}
}
},
'/api/guang/article/detail': {
service: true,
api: URI_PACKAGE_ARTICLE,
... ...