Authored by 陈峰

merge

@@ -14,6 +14,7 @@ @@ -14,6 +14,7 @@
14 </template> 14 </template>
15 15
16 <script> 16 <script>
  17 +import {mapState} from 'vuex';
17 export default { 18 export default {
18 name: 'YohoActionSheet', 19 name: 'YohoActionSheet',
19 props: { 20 props: {
@@ -58,11 +59,18 @@ export default { @@ -58,11 +59,18 @@ export default {
58 }); 59 });
59 }, 60 },
60 computed: { 61 computed: {
  62 + ...mapState(['yoho']),
61 actionCls() { 63 actionCls() {
62 return [{ 'yoho-action-sheet': this.full }]; 64 return [{ 'yoho-action-sheet': this.full }];
63 }, 65 },
64 contentHeight() { 66 contentHeight() {
65 - return this.full ? `${this.maxHeight - 20}px` : 'auto'; 67 + let {statusBarHeight, statusBarStatus} = this.yoho.window || {};
  68 +
  69 + if (!statusBarStatus) {
  70 + statusBarHeight = 0;
  71 + }
  72 +
  73 + return this.full ? `${this.maxHeight - 20 - statusBarHeight}px` : 'auto';
66 } 74 }
67 }, 75 },
68 methods: { 76 methods: {
@@ -124,6 +124,8 @@ export default { @@ -124,6 +124,8 @@ export default {
124 if (params.rootCommentId) { 124 if (params.rootCommentId) {
125 this.page = get(result, 'data.page', 1); 125 this.page = get(result, 'data.page', 1);
126 this.prePage = this.page - 1; 126 this.prePage = this.page - 1;
  127 + } else {
  128 + this.prePage = 0;
127 } 129 }
128 130
129 this.totalPage = get(result, 'data.totalPage', 1); 131 this.totalPage = get(result, 'data.totalPage', 1);
@@ -173,8 +175,8 @@ export default { @@ -173,8 +175,8 @@ export default {
173 let scrollHeight = this.$refs.scroll.$el.offsetHeight; 175 let scrollHeight = this.$refs.scroll.$el.offsetHeight;
174 let dom = this.$refs.commentList.getElementsByClassName('comment-' + this.commentId); 176 let dom = this.$refs.commentList.getElementsByClassName('comment-' + this.commentId);
175 177
176 - if (scrollHeight && dom.length && (dom[0].offsetHeight + dom[0].offsetoffsetTop > scrollHeight)) {  
177 - this.$refs.scroll.scrollTo(0, scrollHeight - this.$refs.commentList.offsetoffsetTop); 178 + if (scrollHeight && dom.length && (dom[0].offsetHeight + dom[0].offsetTop > scrollHeight)) {
  179 + this.$refs.scroll.scrollTo(0, scrollHeight - this.$refs.commentList.offsetHeight);
178 } 180 }
179 }, 500); 181 }, 500);
180 } 182 }
@@ -209,7 +211,7 @@ export default { @@ -209,7 +211,7 @@ export default {
209 onScrollEndHandle(e) { 211 onScrollEndHandle(e) {
210 this.scrollY = e.y; 212 this.scrollY = e.y;
211 213
212 - if (this.prePage < 1) { 214 + if (!this.commentId || this.prePage < 1) {
213 return; 215 return;
214 } 216 }
215 217
1 <template> 1 <template>
2 - <img v-lazy="currentSrc" :alt="alt" v-if="currentLazy" @error="onError"> 2 + <img v-lazy="currentSrc" :alt="alt" v-if="currentLazy" class="lazy-img" @error="onError">
3 <img :src="currentSrc" :alt="alt" v-else lazy="" data-src="" @error="onError"> 3 <img :src="currentSrc" :alt="alt" v-else lazy="" data-src="" @error="onError">
4 </template> 4 </template>
5 5
@@ -26,6 +26,9 @@ export default { @@ -26,6 +26,9 @@ export default {
26 }, 26 },
27 init() { 27 init() {
28 this.$refs.scroll.init(); 28 this.$refs.scroll.init();
  29 + },
  30 + clear() {
  31 + this.$refs.scroll.clear();
29 } 32 }
30 }, 33 },
31 }; 34 };
@@ -156,10 +156,13 @@ export default { @@ -156,10 +156,13 @@ export default {
156 this.getItems(reload); 156 this.getItems(reload);
157 } 157 }
158 }, 158 },
  159 + clear() {
  160 + this.noMore = false;
  161 + this.items = [];
  162 + },
159 getItems(reload) { 163 getItems(reload) {
160 if (reload) { 164 if (reload) {
161 - this.noMore = false;  
162 - this.items = []; 165 + this.clear();
163 } 166 }
164 this.loadings.push('pending'); 167 this.loadings.push('pending');
165 this.onFetch().then((res) => { 168 this.onFetch().then((res) => {
1 <template> 1 <template>
2 - <div class="recycle-scroll-reveal" v-bind="$attrs" v-on="$listeners"> 2 + <div class="recycle-scroll-reveal">
3 <div class="recycle-scroll-reveal-main" ref="scroll"> 3 <div class="recycle-scroll-reveal-main" ref="scroll">
4 <div ref="eternal" class="eternal-top"> 4 <div ref="eternal" class="eternal-top">
5 <slot name="eternalTop"></slot> 5 <slot name="eternalTop"></slot>
@@ -101,11 +101,13 @@ export default { @@ -101,11 +101,13 @@ export default {
101 items(newList, oldList) { 101 items(newList, oldList) {
102 let list = newList.slice(oldList.length, newList.length); 102 let list = newList.slice(oldList.length, newList.length);
103 103
104 - this.loadItems(list, oldList.length).then(() => {  
105 - if (oldList.length < 2) {  
106 - this._updateList();  
107 - }  
108 - }); 104 + if (list.length) {
  105 + this.loadItems(list, oldList.length).then(() => {
  106 + if (oldList.length < 2) {
  107 + this._updateList();
  108 + }
  109 + });
  110 + }
109 } 111 }
110 }, 112 },
111 mounted() { 113 mounted() {
@@ -132,25 +134,25 @@ export default { @@ -132,25 +134,25 @@ export default {
132 this.$el.removeEventListener(EVENT_SCROLL, this.onScroll); 134 this.$el.removeEventListener(EVENT_SCROLL, this.onScroll);
133 }, 135 },
134 methods: { 136 methods: {
135 - resize(index) {  
136 - this.$refs.scroll.resize(index);  
137 - },  
138 init() { 137 init() {
139 this.colsHeight = []; 138 this.colsHeight = [];
140 this.itemWidth = Math.floor(this.$el.offsetWidth / this.cols); 139 this.itemWidth = Math.floor(this.$el.offsetWidth / this.cols);
141 140
  141 + this.load(true);
  142 + },
  143 + clear() {
  144 + this.noMore = false;
  145 + this.items = [];
  146 +
142 for (let i = 0; i < this.cols; i++) { 147 for (let i = 0; i < this.cols; i++) {
143 - this[this.colPrefix + i].length = 0;  
144 - this.visibleItems[i] = this[this.colPrefix + i]; 148 + this.visibleItems[i].length = 0;
145 this.colsHeight[i] = 0; 149 this.colsHeight[i] = 0;
  150 + this.startIndexs[i] = 0;
146 } 151 }
147 -  
148 - this.load(true);  
149 }, 152 },
150 load(reload) { 153 load(reload) {
151 if (reload) { 154 if (reload) {
152 - this.noMore = false;  
153 - this.items = []; 155 + this.clear();
154 } 156 }
155 157
156 if (!reload && (this.loading || this.noMore)) { 158 if (!reload && (this.loading || this.noMore)) {
@@ -222,9 +224,9 @@ export default { @@ -222,9 +224,9 @@ export default {
222 k--; 224 k--;
223 } 225 }
224 } 226 }
225 - });  
226 227
227 - return true; 228 + return true;
  229 + });
228 }, 230 },
229 loadItem(item, colIndex) { 231 loadItem(item, colIndex) {
230 return new Promise(r => { 232 return new Promise(r => {
@@ -289,6 +291,7 @@ export default { @@ -289,6 +291,7 @@ export default {
289 } else { 291 } else {
290 this.$set(col[i], 'placeholder', false); 292 this.$set(col[i], 'placeholder', false);
291 } 293 }
  294 +
292 if (!hasTopItem && col[i].top > top) { 295 if (!hasTopItem && col[i].top > top) {
293 startIndex = Math.max(0, i - 1); 296 startIndex = Math.max(0, i - 1);
294 hasTopItem = true; 297 hasTopItem = true;
@@ -90,7 +90,7 @@ export default { @@ -90,7 +90,7 @@ export default {
90 if (!this.title) { 90 if (!this.title) {
91 let first = get(result, 'data.detailList[0]'); 91 let first = get(result, 'data.detailList[0]');
92 92
93 - this.title = `@${first.authorName} 在有货上发了一篇笔记,快点开看看!`; 93 + this.title = `@${first.authorName} 在有货社区上发了一篇笔记,快点开看看!`;
94 94
95 if (!this.$yoho.isApp) { 95 if (!this.$yoho.isApp) {
96 let shareImage = ''; 96 let shareImage = '';
@@ -146,7 +146,7 @@ export default { @@ -146,7 +146,7 @@ export default {
146 this.CHANGE_ARTICLE_LIST_INTRO_HEIGHT({ 146 this.CHANGE_ARTICLE_LIST_INTRO_HEIGHT({
147 articleId: this.data.articleId, 147 articleId: this.data.articleId,
148 introHeight: get(this.$refs, 'introPool.scrollHeight', 0) + 20, 148 introHeight: get(this.$refs, 'introPool.scrollHeight', 0) + 20,
149 - introCollapseHeight: get(this.$refs, 'intro.scrollHeight', 0), 149 + introCollapseHeight: get(this.$refs, 'intro.offsetHeight', 0),
150 type: this.type 150 type: this.type
151 }); 151 });
152 } 152 }
@@ -172,7 +172,7 @@ export default { @@ -172,7 +172,7 @@ export default {
172 }, 172 },
173 onShare() { 173 onShare() {
174 this.$yoho.share({ 174 this.$yoho.share({
175 - title: `@${this.data.authorName} 在有货上发了一篇笔记,快点开看看!`, 175 + title: `@${this.data.authorName} 在有货社区上发了一篇笔记,快点开看看!`,
176 imgUrl: this.data.shareImage, 176 imgUrl: this.data.shareImage,
177 link: `${location.origin}/grass/article/share/${this.data.articleId}`, 177 link: `${location.origin}/grass/article/share/${this.data.articleId}`,
178 desc: this.data.intro, 178 desc: this.data.intro,
@@ -75,7 +75,7 @@ export default { @@ -75,7 +75,7 @@ export default {
75 }, 75 },
76 favOption() { 76 favOption() {
77 return { 77 return {
78 - selected: this.articleState.hasPraised === 'Y', 78 + selected: this.articleState.hasPraise === 'Y',
79 iconBold: true, 79 iconBold: true,
80 iconFontSize: 30, 80 iconFontSize: 30,
81 textAlign: 'normal' 81 textAlign: 'normal'
1 <template> 1 <template>
2 <Layout class="article"> 2 <Layout class="article">
3 - <LayoutHeader v-if="!noHeader" theme="white" slot='header' :title="title"> 3 + <LayoutHeader v-if="!noHeader" theme="white" slot='header'>
4 <template v-if="showHeader"> 4 <template v-if="showHeader">
5 <div class="avatar-wrapper" @click="toUserPage"> 5 <div class="avatar-wrapper" @click="toUserPage">
6 <WidgetAvatar class="widget-avatar" :src="currentAuthor.authorHeadIco" :width="70" :height="70"></WidgetAvatar> 6 <WidgetAvatar class="widget-avatar" :src="currentAuthor.authorHeadIco" :width="70" :height="70"></WidgetAvatar>
7 <span class="user-name">{{currentAuthor.authorName}}</span> 7 <span class="user-name">{{currentAuthor.authorName}}</span>
8 </div> 8 </div>
9 </template> 9 </template>
  10 + <template v-else>
  11 + <div class="article-title">{{title}}</div>
  12 + </template>
10 <template v-if="showHeader" v-slot:opts> 13 <template v-if="showHeader" v-slot:opts>
11 <WidgetFollow :share="share" class="widget-follow" :class="headerFollowClass" :author-uid="currentAuthor.authorUid" :follow="currentAuthor.hasAttention === 'Y'" @on-follow="follow => onFollow(currentAuthor, follow)" :pos-id="posId"></WidgetFollow> 14 <WidgetFollow :share="share" class="widget-follow" :class="headerFollowClass" :author-uid="currentAuthor.authorUid" :follow="currentAuthor.hasAttention === 'Y'" @on-follow="follow => onFollow(currentAuthor, follow)" :pos-id="posId"></WidgetFollow>
12 <i class="iconfont icon-more1" @click="onShowMore(currentAuthor)"></i> 15 <i class="iconfont icon-more1" @click="onShowMore(currentAuthor)"></i>
@@ -67,7 +70,7 @@ export default { @@ -67,7 +70,7 @@ export default {
67 props: { 70 props: {
68 title: { 71 title: {
69 type: String, 72 type: String,
70 - default: '' 73 + default: '有货社区'
71 }, 74 },
72 share: Boolean, 75 share: Boolean,
73 type: String, 76 type: String,
@@ -200,6 +203,10 @@ export default { @@ -200,6 +203,10 @@ export default {
200 onDounceScroll({item, scrollTop, startIndex}) { 203 onDounceScroll({item, scrollTop, startIndex}) {
201 this.scrollTop = scrollTop; 204 this.scrollTop = scrollTop;
202 205
  206 + if (item) {
  207 + this.reportShow(startIndex, item);
  208 + }
  209 +
203 // 产品要求去掉头部交互 210 // 产品要求去掉头部交互
204 return; 211 return;
205 212
@@ -230,8 +237,6 @@ export default { @@ -230,8 +237,6 @@ export default {
230 this.currentAuthor.index = item.index; 237 this.currentAuthor.index = item.index;
231 238
232 this.showHeader = true; 239 this.showHeader = true;
233 -  
234 - this.reportShow(startIndex, item);  
235 } 240 }
236 }, 241 },
237 init() { 242 init() {
@@ -358,6 +363,11 @@ export default { @@ -358,6 +363,11 @@ export default {
358 white-space: nowrap; 363 white-space: nowrap;
359 } 364 }
360 365
  366 +.article-title {
  367 + font-size: 34px;
  368 + font-weight: 500;
  369 +}
  370 +
361 .icon-more1 { 371 .icon-more1 {
362 font-size: 40px!important; 372 font-size: 40px!important;
363 margin-right: 6px; 373 margin-right: 6px;
@@ -220,8 +220,8 @@ export default { @@ -220,8 +220,8 @@ export default {
220 }, 400); 220 }, 400);
221 221
222 this.scrollEvent(params); 222 this.scrollEvent(params);
223 -  
224 - setTimeout(() => { 223 + this._ttTimer && clearTimeout(this._ttTimer);
  224 + this._ttTimer = setTimeout(() => {
225 this.scrollEvent(params); 225 this.scrollEvent(params);
226 }, throttleTime) 226 }, throttleTime)
227 }, 227 },
@@ -251,62 +251,62 @@ export default { @@ -251,62 +251,62 @@ export default {
251 this.page = 1; 251 this.page = 1;
252 this.headerAnimateStep = 0; 252 this.headerAnimateStep = 0;
253 253
254 - this.fetchTopicSimpleInfo({topicId: this.topicId}).then(res => {  
255 - let {topicName, topicImageUrl, topicDesc} = get(res, 'data') || {};  
256 -  
257 - if (this.share) {  
258 - document && (document.title = topicName);  
259 - }  
260 -  
261 - if (this.share && !this.$yoho.isApp && res.code === 200) {  
262 - Share.setShareInfo({  
263 - title: topicName,  
264 - imgUrl: topicImageUrl,  
265 - desc: '我在有货的社区发现一个热门话题。' + topicDesc,  
266 - });  
267 - }  
268 -  
269 - if (!topicImageUrl) {  
270 - this.headerAnimateStep = 100;  
271 - } 254 + if (this.$refs.scroll) {
  255 + this.$refs.scroll.$el.scrollTop = 0;
  256 + this.$refs.scroll.clear();
  257 + }
272 258
  259 + return this.load().then(() => {
273 this.$nextTick(() => { 260 this.$nextTick(() => {
274 - if (this.$refs.scroll) {  
275 - this.$refs.scroll.$el.scrollTop = 0;  
276 - this.$refs.scroll.init();  
277 - } 261 + this.$refs.scroll && this.$refs.scroll.init();
278 }); 262 });
279 }); 263 });
280 }, 264 },
  265 + load() {
  266 + this.listPreCache = {};
  267 +
  268 + return Promise.all([
  269 + this.fetchTopicSimpleInfo({topicId: this.topicId}).then(res => {
  270 + if (res.code === 200) {
  271 + this.setPageShareInfo(get(res, 'data', {}));
  272 + }
  273 +
  274 + if (!get(res, 'data.topicImageUrl')) {
  275 + this.headerAnimateStep = 100;
  276 + }
  277 + }),
  278 + this.fetchTopicRelatedArticles({topicId: this.topicId, page: 1}).then(res => {
  279 + if (res.code === 200) {
  280 + this.listPreCache[`${this.topicId}-1`] = res;
  281 + }
  282 + })
  283 + ]);
  284 + },
281 async onFetch() { 285 async onFetch() {
282 const topicId = parseInt(this.topicId, 10); 286 const topicId = parseInt(this.topicId, 10);
283 287
284 - if (!topicId) {  
285 - return; 288 + if (!topicId || this.fetching) {
  289 + return [];
286 } 290 }
287 291
  292 + this.fetching = true;
288 this.page = this.page || 1; 293 this.page = this.page || 1;
289 294
290 - const result = await this.fetchTopicRelatedArticles({  
291 - topicId,  
292 - page: this.page  
293 - }); 295 + let result = get(this.listPreCache, `${this.topicId}-${this.page}`);
  296 +
  297 + if (!result) {
  298 + result = await this.fetchTopicRelatedArticles({
  299 + topicId,
  300 + page: this.page
  301 + });
  302 + }
294 303
  304 + this.fetching = false;
295 let list = []; 305 let list = [];
296 306
297 if (result.code === 200) { 307 if (result.code === 200) {
298 this.page++; 308 this.page++;
299 list = get(result, 'data.detailList', []); 309 list = get(result, 'data.detailList', []);
300 -  
301 - if (list.length) {  
302 - this.$sdk.getUser().then(user => {  
303 - if (user && user.uid) {  
304 - this.fetchArticleProductFavs({  
305 - articles: list  
306 - });  
307 - }  
308 - });  
309 - }  
310 } else { 310 } else {
311 this.$createToast && this.$createToast({ 311 this.$createToast && this.$createToast({
312 txt: result.message || '服务器开小差了', 312 txt: result.message || '服务器开小差了',
@@ -316,7 +316,7 @@ export default { @@ -316,7 +316,7 @@ export default {
316 } 316 }
317 317
318 return new Promise(resolve => { 318 return new Promise(resolve => {
319 - if (this.topicInfo.viewModel === 1 && this.page <= 2) { 319 + if (get(this.topicInfo, 'viewModel') === 1 && this.page <= 2) {
320 list = [{topicHead: true}, ...list]; 320 list = [{topicHead: true}, ...list];
321 } 321 }
322 322
@@ -348,6 +348,19 @@ export default { @@ -348,6 +348,19 @@ export default {
348 this.$refs.actionSheet.show(params); 348 this.$refs.actionSheet.show(params);
349 }); 349 });
350 }, 350 },
  351 + setPageShareInfo({topicName, topicImageUrl, topicDesc}) {
  352 + if (this.share) {
  353 + document && (document.title = topicName || '话题');
  354 +
  355 + if (!this.$yoho.isApp) {
  356 + Share.setShareInfo({
  357 + title: topicName,
  358 + imgUrl: topicImageUrl,
  359 + desc: '我在有货的社区发现一个热门话题。' + topicDesc,
  360 + });
  361 + }
  362 + }
  363 + },
351 startReportShow() { 364 startReportShow() {
352 let preview = null; 365 let preview = null;
353 let name = this.$yoho.isiOS ? 'iFP_ArticleList' : 'aFP_ArticleList'; 366 let name = this.$yoho.isiOS ? 'iFP_ArticleList' : 'aFP_ArticleList';
@@ -611,6 +611,11 @@ ul { @@ -611,6 +611,11 @@ ul {
611 white-space: nowrap; 611 white-space: nowrap;
612 } 612 }
613 613
  614 +img.lazy-img {
  615 + opacity: 0;
  616 + transition: opacity 800ms ease-in-out;
  617 +}
  618 +
614 img[lazy=loading] { 619 img[lazy=loading] {
615 opacity: 0.2; 620 opacity: 0.2;
616 } 621 }
@@ -163,7 +163,6 @@ export default { @@ -163,7 +163,6 @@ export default {
163 }); 163 });
164 }, 164 },
165 [Types.CHANGE_ARTICLE_LIST_SLIDE](state, {articleId, index, type}) { 165 [Types.CHANGE_ARTICLE_LIST_SLIDE](state, {articleId, index, type}) {
166 - console.log(articleId, index, type);  
167 state[articlefield(type)].forEach(article => { 166 state[articlefield(type)].forEach(article => {
168 if (article.articleId === articleId) { 167 if (article.articleId === articleId) {
169 article.blockIndex = index; 168 article.blockIndex = index;
@@ -60,7 +60,7 @@ class Day { @@ -60,7 +60,7 @@ class Day {
60 const days = Math.floor((today - date) / (24 * 60 * 60 * 1000)) + 1; 60 const days = Math.floor((today - date) / (24 * 60 * 60 * 1000)) + 1;
61 61
62 if (days > 5) { 62 if (days > 5) {
63 - return `${this.year()}-${this._fix(this.month(), 2)}-${this._fix(this.day(), 2)}`; 63 + return `${this.year()}-${this._fix(this.month(), 2)}-${this._fix(this.date(), 2)}`;
64 } else if (days > 2) { 64 } else if (days > 2) {
65 return '2天前'; 65 return '2天前';
66 } else if (days > 1) { 66 } else if (days > 1) {
@@ -17,7 +17,15 @@ const setStatusBar = (width, height, store) => { @@ -17,7 +17,15 @@ const setStatusBar = (width, height, store) => {
17 height: statusBar.statusBarHeight 17 height: statusBar.statusBarHeight
18 }); 18 });
19 19
20 - if (version(cookie.get('app_version'),' 6.9.2') >= 0) { 20 + function getAppVersion(str, split) {
  21 + const match = str.match(new RegExp('(^|)app_version=([^' + split + ']*)(' + split + '|$)'));
  22 +
  23 + return match && match.length ? match[2] : '';
  24 + }
  25 +
  26 + const appVersion = getAppVersion(document.cookie, ';') || getAppVersion(location.href, '&');
  27 +
  28 + if (version(appVersion, '6.9.2') >= 0) {
21 statusBar.statusBarStatus = true; 29 statusBar.statusBarStatus = true;
22 store && store.commit('SET_STATUS_BAR_STATUS', {status: true}); 30 store && store.commit('SET_STATUS_BAR_STATUS', {status: true});
23 } 31 }
@@ -15,6 +15,7 @@ const checkRefer = helpers.urlFormat('/3party/check', {refer: replaceKey}); @@ -15,6 +15,7 @@ const checkRefer = helpers.urlFormat('/3party/check', {refer: replaceKey});
15 */ 15 */
16 exports.serverError = (err, req, res, next) => { // eslint-disable-line 16 exports.serverError = (err, req, res, next) => { // eslint-disable-line
17 err = err || {}; 17 err = err || {};
  18 +
18 logger.error(`error at path: ${req.url}`); 19 logger.error(`error at path: ${req.url}`);
19 logger.error(`${req.url},${typeof err === 'object' ? JSON.stringify(err) : err}`); 20 logger.error(`${req.url},${typeof err === 'object' ? JSON.stringify(err) : err}`);
20 21
@@ -2,7 +2,6 @@ const _ = require('lodash'); @@ -2,7 +2,6 @@ const _ = require('lodash');
2 2
3 module.exports = (result, apiInfo) => { 3 module.exports = (result, apiInfo) => {
4 if (result.code === 200 && _.isObject(apiInfo.fields)) { 4 if (result.code === 200 && _.isObject(apiInfo.fields)) {
5 - console.log(apiInfo.fields);  
6 let resData = result.data || {}; 5 let resData = result.data || {};
7 let data = {}; 6 let data = {};
8 7