Merge branch 'feature/userPage'
Showing
7 changed files
with
951 additions
and
4 deletions
apps/pages/userpage/author.vue
0 → 100644
1 | +<template> | ||
2 | + <Layout class="author-page"> | ||
3 | + <LayoutHeader slot='header' theme="white"> | ||
4 | + <div ref="headerAuthor" class="header-author"> | ||
5 | + <div class="h-name flex">{{baseData.nickName}}</div> | ||
6 | + <div class="h-more"> | ||
7 | + <div class="flex"> | ||
8 | + <WidgetAvatar v-if="baseData.headIco" class="h-headico" :src="baseData.headIco" :width="100" :height="100"></WidgetAvatar> | ||
9 | + </div> | ||
10 | + <div class="h-follow flex"> | ||
11 | + <WidgetFollow class="widget-follow" :author-uid="autherInfo.authorUid" :follow="isAttention" @on-follow="follow => onFollow(follow)"></WidgetFollow> | ||
12 | + </div> | ||
13 | + </div> | ||
14 | + </div> | ||
15 | + <template v-slot:opts> | ||
16 | + <WidgetShare class="header-share"></WidgetShare> | ||
17 | + </template> | ||
18 | + </LayoutHeader> | ||
19 | + <cube-sticky :pos="scrollY"> | ||
20 | + <cube-scroll | ||
21 | + class="main-container" | ||
22 | + :scroll-events="scrollEvents" | ||
23 | + @scroll="scrollHandler"> | ||
24 | + <div ref="authorProfile" class="author-profile"> | ||
25 | + <span class="avatar-box"> | ||
26 | + <WidgetAvatar v-if="baseData.headIco" :src="baseData.headIco" :width="100" :height="100"></WidgetAvatar> | ||
27 | + </span> | ||
28 | + <div class="author-section"> | ||
29 | + <ul class="author-fans"> | ||
30 | + <li> | ||
31 | + <span class="num">{{baseData.attCount}}</span> | ||
32 | + <p class="name"> | ||
33 | + <span>关注</span> | ||
34 | + </p> | ||
35 | + </li> | ||
36 | + <li> | ||
37 | + <span class="num">{{baseData.fansCount}}</span> | ||
38 | + <p class="name"> | ||
39 | + <span>粉丝</span> | ||
40 | + </p> | ||
41 | + </li> | ||
42 | + <li> | ||
43 | + <span class="num">{{baseData.praiseAndfavorite}}</span> | ||
44 | + <p class="name"> | ||
45 | + <span>获赞与收藏</span> | ||
46 | + </p> | ||
47 | + </li> | ||
48 | + </ul> | ||
49 | + <div class="operate-wrap"> | ||
50 | + <label v-if="isOwner" class="operate-btn btn-user-edit">编辑个人资料</label> | ||
51 | + <WidgetFollow v-else class="operate-btn" :author-uid="autherInfo.authorUid" :follow="isAttention" @on-follow="follow => onFollow(follow)"></WidgetFollow> | ||
52 | + </div> | ||
53 | + </div> | ||
54 | + </div> | ||
55 | + <p v-if="baseData.signature" class="author-desc">{{baseData.signature}}</p> | ||
56 | + <cube-sticky-ele ele-key="11"> | ||
57 | + <FavTabBlock :tabs-num="tabsNum" :active-index="activeIndex" @change="changeTab"></FavTabBlock> | ||
58 | + </cube-sticky-ele> | ||
59 | + <div class="contant-list"> | ||
60 | + <WaterFall class="pannel-wrap" :list="list" :pos="scrollY"></WaterFall> | ||
61 | + </div> | ||
62 | + | ||
63 | + <div v-if="loadStatus" class="loading"> | ||
64 | + <Loading v-if="loadStatus === 1" class="load-icon" :size="20"></Loading> | ||
65 | + <p v-else class="load-text">没有更多了</p> | ||
66 | + </div> | ||
67 | + </cube-scroll> | ||
68 | + <template slot="fixed" slot-scope="props"> | ||
69 | + <FavTabBlock :tabs-num="tabsNum" :active-index="activeIndex" @change="changeTab"></FavTabBlock> | ||
70 | + </template> | ||
71 | + </cube-sticky> | ||
72 | + </Layout> | ||
73 | +</template> | ||
74 | + | ||
75 | +<script> | ||
76 | + import {assign, get} from 'lodash'; | ||
77 | + import {Scroll, Sticky, Loading} from 'cube-ui'; | ||
78 | + import CubeStickyEle from 'cube-ui/src/components/sticky/sticky-ele.vue'; | ||
79 | + import FavTabBlock from './components/fav-tab-block'; | ||
80 | + import WaterFall from './components/water-fall'; | ||
81 | + | ||
82 | + import {createNamespacedHelpers} from 'vuex'; | ||
83 | + const {mapActions} = createNamespacedHelpers('user'); | ||
84 | + | ||
85 | + export default { | ||
86 | + name: 'userpage', | ||
87 | + data() { | ||
88 | + return { | ||
89 | + autherInfo: {}, | ||
90 | + scrollEvents: ['scroll'], | ||
91 | + scrollY: 0, | ||
92 | + baseData: {}, | ||
93 | + isAttention: false, | ||
94 | + isOwner: false, | ||
95 | + tabsNum: [10, 0], | ||
96 | + activeIndex: 0, | ||
97 | + fetchInfo: {}, | ||
98 | + loadStatus: '' | ||
99 | + } | ||
100 | + }, | ||
101 | + created() { | ||
102 | + this.autherInfo = { | ||
103 | + authorUid: +this.$route.params.id, | ||
104 | + authorType: this.$route.params.type | ||
105 | + }; | ||
106 | + | ||
107 | + this.fetchBaseInfo(); | ||
108 | + this.fetchList(); | ||
109 | + }, | ||
110 | + mounted() { | ||
111 | + let $dom = this.$refs.headerAuthor; | ||
112 | + | ||
113 | + if ($dom.offsetHeight) { | ||
114 | + this._animeDuration = 300; | ||
115 | + import('animejs').then(({default: anime}) => { | ||
116 | + this._animeEl = anime({ | ||
117 | + targets: $dom, | ||
118 | + translateY: -$dom.offsetHeight, | ||
119 | + easing: 'easeInOutSine', | ||
120 | + duration: this._animeDuration, | ||
121 | + autoplay: false | ||
122 | + }); | ||
123 | + }); | ||
124 | + } | ||
125 | + }, | ||
126 | + watch: { | ||
127 | + scrollY(top) { | ||
128 | + let animePlayed = false; | ||
129 | + | ||
130 | + if (top > this.$refs.authorProfile.offsetHeight) { | ||
131 | + animePlayed = true; | ||
132 | + } | ||
133 | + | ||
134 | + if (!this._animePlayed === !animePlayed) { | ||
135 | + return; | ||
136 | + } | ||
137 | + | ||
138 | + let start; | ||
139 | + let self = this; | ||
140 | + | ||
141 | + function step(timestamp) { | ||
142 | + if (!start) { | ||
143 | + start = timestamp | ||
144 | + }; | ||
145 | + | ||
146 | + let progress = Math.floor(timestamp - start); | ||
147 | + | ||
148 | + self._animeEl.seek(animePlayed ? progress : self._animeDuration - progress); | ||
149 | + | ||
150 | + if (progress < self._animeDuration) { | ||
151 | + window.requestAnimationFrame(step); | ||
152 | + } | ||
153 | + }; | ||
154 | + | ||
155 | + window.requestAnimationFrame(step); | ||
156 | + | ||
157 | + this._animePlayed = animePlayed; | ||
158 | + } | ||
159 | + }, | ||
160 | + computed: { | ||
161 | + list() { | ||
162 | + return get(this.fetchInfo, `${this.activeIndex}.list`) || []; | ||
163 | + } | ||
164 | + }, | ||
165 | + methods: { | ||
166 | + ...mapActions(['autherBaseInfo', 'autherAritcleNum', 'autherPubList', 'autherFavList']), | ||
167 | + scrollHandler({ y }) { | ||
168 | + this.scrollY = -y; | ||
169 | + | ||
170 | + if (this.scrollY + 1000 > this.$el.offsetHeight) { | ||
171 | + this._listTimer && clearTimeout(this._listTimer); | ||
172 | + this._listTimer = setTimeout(() => { | ||
173 | + this.fetchList(); | ||
174 | + }, 100); | ||
175 | + } | ||
176 | + }, | ||
177 | + changeTab(index) { | ||
178 | + if (this.activeIndex !== index) { | ||
179 | + this.activeIndex = index; | ||
180 | + this.fetchList(); | ||
181 | + } | ||
182 | + }, | ||
183 | + fetchBaseInfo() { | ||
184 | + this.autherBaseInfo(this.autherInfo).then(res => { | ||
185 | + if (res.code === 200) { | ||
186 | + this.baseData = res.data; | ||
187 | + this.isOwner = res.data.isOwner; | ||
188 | + this.isAttention = res.data.isAttention === 'Y'; | ||
189 | + } | ||
190 | + }); | ||
191 | + | ||
192 | + this.autherAritcleNum(this.autherInfo).then(res => { | ||
193 | + this.tabsNum = [get(res, 'data.articleCount'), get(res, 'data.favoriteCount')]; | ||
194 | + }); | ||
195 | + }, | ||
196 | + async fetchList() { | ||
197 | + this.fetchInfo = this.fetchInfo || []; | ||
198 | + | ||
199 | + if (this.syncing) { | ||
200 | + return; | ||
201 | + } | ||
202 | + | ||
203 | + let info = this.fetchInfo[this.activeIndex] || {}; | ||
204 | + let result; | ||
205 | + | ||
206 | + info.page = info.page || 1; | ||
207 | + | ||
208 | + if (info.page >= info.totalPage) { | ||
209 | + return; | ||
210 | + } | ||
211 | + | ||
212 | + let syncServiceName; | ||
213 | + | ||
214 | + if (this.activeIndex === 1) { | ||
215 | + syncServiceName = 'autherFavList'; | ||
216 | + } else { | ||
217 | + syncServiceName = 'autherPubList'; | ||
218 | + } | ||
219 | + | ||
220 | + if (this[syncServiceName]) { | ||
221 | + this.syncing = true; | ||
222 | + result = await this[syncServiceName](assign({ | ||
223 | + page: info.page, | ||
224 | + lastedTime: info.lastedTime || '' | ||
225 | + }, this.autherInfo)); | ||
226 | + this.syncing = false; | ||
227 | + } | ||
228 | + | ||
229 | + if (result.code === 200) { | ||
230 | + info.list = (info.list || []).concat(result.data.list); | ||
231 | + info.page++; | ||
232 | + info.totalPage = 10 || result.data.totalPage; | ||
233 | + info.lastedTime = result.data.lastedTime; | ||
234 | + } | ||
235 | + | ||
236 | + if (info.page > info.totalPage) { | ||
237 | + this.loadStatus = 2; | ||
238 | + } else { | ||
239 | + this.loadStatus = 1; | ||
240 | + } | ||
241 | + | ||
242 | + this.fetchInfo[this.activeIndex] = info; | ||
243 | + | ||
244 | + this.fetchInfo = {...this.fetchInfo}; | ||
245 | + }, | ||
246 | + onFollow(follow) { | ||
247 | + this.isAttention = follow; | ||
248 | + } | ||
249 | + }, | ||
250 | + components: { | ||
251 | + CubeScroll: Scroll, | ||
252 | + CubeSticky: Sticky, | ||
253 | + CubeStickyEle, | ||
254 | + Loading, | ||
255 | + FavTabBlock, | ||
256 | + WaterFall | ||
257 | + } | ||
258 | + }; | ||
259 | +</script> | ||
260 | + | ||
261 | + | ||
262 | +<style lang="scss"> | ||
263 | + .author-page { | ||
264 | + box-sizing: border-box; | ||
265 | + color: #4a4a4a; | ||
266 | + } | ||
267 | + | ||
268 | + .header-author { | ||
269 | + width: 100%; | ||
270 | + height: 100%; | ||
271 | + position: relative; | ||
272 | + | ||
273 | + .flex { | ||
274 | + height: 100%; | ||
275 | + display: flex; | ||
276 | + align-items: center; | ||
277 | + justify-content: center; | ||
278 | + } | ||
279 | + | ||
280 | + .h-name { | ||
281 | + font-size: 36px; | ||
282 | + font-weight: 500; | ||
283 | + } | ||
284 | + | ||
285 | + .h-more { | ||
286 | + width: 100%; | ||
287 | + height: 100%; | ||
288 | + position: absolute; | ||
289 | + top: 100%; | ||
290 | + left: 0; | ||
291 | + } | ||
292 | + | ||
293 | + .h-headico { | ||
294 | + width: 60px; | ||
295 | + height: 60px; | ||
296 | + } | ||
297 | + | ||
298 | + .h-follow { | ||
299 | + position: absolute; | ||
300 | + top: 0; | ||
301 | + right: -50px; | ||
302 | + } | ||
303 | + } | ||
304 | + | ||
305 | + | ||
306 | + .header-share { | ||
307 | + margin-right: 26px; | ||
308 | + color: #222; | ||
309 | + font-weight: bold; | ||
310 | + } | ||
311 | + | ||
312 | + .author-profile { | ||
313 | + padding: 24px 30px; | ||
314 | + display: flex; | ||
315 | + justify-content: space-between; | ||
316 | + | ||
317 | + .avatar-box { | ||
318 | + width: 150px; | ||
319 | + height: 150px; | ||
320 | + overflow: hidden; | ||
321 | + border-radius: 50%; | ||
322 | + | ||
323 | + > img { | ||
324 | + width: 100%; | ||
325 | + height: 100%; | ||
326 | + display: block; | ||
327 | + } | ||
328 | + } | ||
329 | + } | ||
330 | + | ||
331 | + .author-section { | ||
332 | + display: flex; | ||
333 | + flex-direction: column; | ||
334 | + justify-content: space-between; | ||
335 | + } | ||
336 | + | ||
337 | + .author-fans { | ||
338 | + display: flex; | ||
339 | + justify-content: flex-end; | ||
340 | + padding-top: 4px; | ||
341 | + padding-right: 54px; | ||
342 | + | ||
343 | + li { | ||
344 | + margin-left: 140px; | ||
345 | + position: relative; | ||
346 | + | ||
347 | + &:first-child { | ||
348 | + margin-left: 0; | ||
349 | + } | ||
350 | + | ||
351 | + .num { | ||
352 | + font-size: 28px; | ||
353 | + font-weight: 500; | ||
354 | + padding-bottom: 6px; | ||
355 | + display: block; | ||
356 | + } | ||
357 | + | ||
358 | + .name { | ||
359 | + position: absolute; | ||
360 | + word-break: keep-all; | ||
361 | + font-size: 20px; | ||
362 | + font-weight: 300; | ||
363 | + color: #9b9b9b; | ||
364 | + margin-left: 50%; | ||
365 | + | ||
366 | + > * { | ||
367 | + position: relative; | ||
368 | + left: -50%; | ||
369 | + } | ||
370 | + } | ||
371 | + } | ||
372 | + } | ||
373 | + | ||
374 | + .operate-wrap { | ||
375 | + text-align: right; | ||
376 | + | ||
377 | + .operate-btn { | ||
378 | + width: calc(100% - 20px); | ||
379 | + font-size: 23px; | ||
380 | + line-height: 48px; | ||
381 | + display: inline-block; | ||
382 | + } | ||
383 | + | ||
384 | + .btn-user-edit { | ||
385 | + color: #222; | ||
386 | + border: 1px solid #4a4a4a; | ||
387 | + border-radius: 8px; | ||
388 | + text-align: center; | ||
389 | + } | ||
390 | + } | ||
391 | + | ||
392 | + .author-desc { | ||
393 | + margin: 20px 30px; | ||
394 | + font-size: 24px; | ||
395 | + font-weight: 300; | ||
396 | + overflow: hidden; | ||
397 | + text-overflow: ellipsis; | ||
398 | + white-space: nowrap; | ||
399 | + } | ||
400 | + | ||
401 | + .loading { | ||
402 | + padding: 20px 0; | ||
403 | + | ||
404 | + .load-icon > span { | ||
405 | + margin: auto; | ||
406 | + } | ||
407 | + | ||
408 | + .load-text { | ||
409 | + text-align: center; | ||
410 | + } | ||
411 | + } | ||
412 | +</style> |
1 | +<template> | ||
2 | + <div class="tabs-wrap"> | ||
3 | + <ul class="tabs-list"> | ||
4 | + <li v-for="(item, index) in tabList" :key="index" :class="{'active': active === index}" @click="changeType(index, true)"> | ||
5 | + {{item.name}} | ||
6 | + <span v-if="item.num" class="t-num">({{item.num}})</span> | ||
7 | + </li> | ||
8 | + </ul> | ||
9 | + </div> | ||
10 | +</template> | ||
11 | + | ||
12 | + | ||
13 | +<script> | ||
14 | +import {find} from 'lodash'; | ||
15 | + | ||
16 | +export default { | ||
17 | + props: { | ||
18 | + tabsNum: Array, | ||
19 | + activeIndex: Number | ||
20 | + }, | ||
21 | + data() { | ||
22 | + return { | ||
23 | + tabList: [ | ||
24 | + {name: '内容', type: 1}, | ||
25 | + {name: '收藏', type: 2}, | ||
26 | + ], | ||
27 | + active: '' | ||
28 | + }; | ||
29 | + }, | ||
30 | + created() { | ||
31 | + this.changeType(this.activeIndex); | ||
32 | + this.computetabsNum(); | ||
33 | + }, | ||
34 | + methods: { | ||
35 | + changeType(index, isClick) { | ||
36 | + if (!this.tabList[index]) { | ||
37 | + index = 0; | ||
38 | + } | ||
39 | + | ||
40 | + this.active = index; | ||
41 | + | ||
42 | + this.$emit('change', index); | ||
43 | + }, | ||
44 | + computetabsNum(a) { | ||
45 | + let tabList = this.tabList; | ||
46 | + | ||
47 | + for (let i = this.tabList.length - 1; i >= 0; i--) { | ||
48 | + let num = ''; | ||
49 | + | ||
50 | + if (this.tabsNum[i] > 0) { | ||
51 | + num = this.tabsNum[i]; | ||
52 | + } | ||
53 | + | ||
54 | + tabList[i].num = num; | ||
55 | + } | ||
56 | + | ||
57 | + this.tabList = [...tabList]; | ||
58 | + }, | ||
59 | + computeCurrentTab() { | ||
60 | + this.changeType(this.activeIndex || 0); | ||
61 | + } | ||
62 | + }, | ||
63 | + watch: { | ||
64 | + tabsNum: 'computetabsNum', | ||
65 | + activeIndex: 'computeCurrentTab' | ||
66 | + } | ||
67 | +}; | ||
68 | +</script> | ||
69 | + | ||
70 | + | ||
71 | +<style> | ||
72 | + .tabs-wrap { | ||
73 | + padding: 20px 30px 30px; | ||
74 | + background-color: #fff; | ||
75 | + display: flex; | ||
76 | + justify-content: space-between; | ||
77 | + align-items: center; | ||
78 | + | ||
79 | + .tabs-list { | ||
80 | + display: flex; | ||
81 | + | ||
82 | + li { | ||
83 | + font-size: 32px; | ||
84 | + color: #b0b0b0; | ||
85 | + font-weight: 300; | ||
86 | + margin-right: 40px; | ||
87 | + } | ||
88 | + | ||
89 | + .active { | ||
90 | + color: #222; | ||
91 | + font-weight: 500; | ||
92 | + position: relative; | ||
93 | + | ||
94 | + &:after { | ||
95 | + content: ''; | ||
96 | + position: absolute; | ||
97 | + left: 0; | ||
98 | + bottom: -10px; | ||
99 | + width: 100%; | ||
100 | + height: 8px; | ||
101 | + background-color: #d90025; | ||
102 | + box-shadow: 0 2px 4px 0 rgba(210, 0, 13, 0.34); | ||
103 | + } | ||
104 | + } | ||
105 | + | ||
106 | + .t-num { | ||
107 | + color: #b0b0b0; | ||
108 | + font-size: 24px; | ||
109 | + zoom: 0.9; | ||
110 | + margin-left: -8px; | ||
111 | + } | ||
112 | + } | ||
113 | + } | ||
114 | +</style> |
1 | +<template> | ||
2 | + <div class="wf-list" :style="{'height': listHeight + 'px'}"> | ||
3 | + <div | ||
4 | + v-for="i in viewList" | ||
5 | + :key="`${i._temporary ? '_' : ''}${i.articleId}`" | ||
6 | + class="wf-item" | ||
7 | + :class="{'wf-item-default': i._default, 'wf-item-temp': i._temporary}" | ||
8 | + :style="`width: ${100 / cols}%;transform: translate(${i.left}px, ${i.top}px)`"> | ||
9 | + <div class="wf-item-mid"> | ||
10 | + <router-link :to="'/article/' + i.articleId"> | ||
11 | + <div class="layer-image" :style="{'height': i.coverHeight + 'px'}"> | ||
12 | + <ImageFormat v-if="!i._temporary" :src="i[srcKey]" :width="coverImageWidth" :height="i.coverHeight"></ImageFormat> | ||
13 | + </div> | ||
14 | + <div class="description">{{i.content}}</div> | ||
15 | + </router-link> | ||
16 | + | ||
17 | + <div class="attribution"> | ||
18 | + <router-link :to="'/article/' + i.articleId" class="auther"> | ||
19 | + <span class="avatar"> | ||
20 | + <WidgetAvatar v-if="!i._temporary" :src="i.authorHeadIco" :width="70" :height="70"></WidgetAvatar> | ||
21 | + </span> | ||
22 | + <span class="name">{{i.authorName}}</span> | ||
23 | + </router-link> | ||
24 | + | ||
25 | + <div class="fav"> | ||
26 | + <WidgetFav :articleId="i.articleId" :num="i.praiseCount" :option="favOption"></WidgetFav> | ||
27 | + </div> | ||
28 | + </div> | ||
29 | + </div> | ||
30 | + </div> | ||
31 | + </div> | ||
32 | +</template> | ||
33 | + | ||
34 | +<script> | ||
35 | +import {assign} from 'lodash'; | ||
36 | + | ||
37 | +export default { | ||
38 | + data() { | ||
39 | + return { | ||
40 | + viewList: [{ | ||
41 | + _default: true | ||
42 | + }], | ||
43 | + coverImageWidth: 0, | ||
44 | + colWidthPer: 0, | ||
45 | + calcIndex: 0, | ||
46 | + loadedIndex: 0, | ||
47 | + colsHeight: [], | ||
48 | + favOption: { | ||
49 | + iconFontSize: 26, | ||
50 | + textAlign: 'normal' | ||
51 | + } | ||
52 | + } | ||
53 | + }, | ||
54 | + props: { | ||
55 | + pos: { | ||
56 | + type: Number, | ||
57 | + default: 0 | ||
58 | + }, | ||
59 | + list: { | ||
60 | + type: Array, | ||
61 | + default: [] | ||
62 | + }, | ||
63 | + srcKey: { | ||
64 | + type: String, | ||
65 | + default: 'coverImage' | ||
66 | + }, | ||
67 | + cols: { | ||
68 | + type: Number, | ||
69 | + default: 2 | ||
70 | + }, | ||
71 | + space: { | ||
72 | + type: Number, | ||
73 | + default: 14 | ||
74 | + } | ||
75 | + }, | ||
76 | + mounted() { | ||
77 | + this.$on('calced', (nlist) => { | ||
78 | + this.viewList = this.viewList.concat(nlist); | ||
79 | + this.$nextTick(() => { | ||
80 | + this.calcLayout(); | ||
81 | + }) | ||
82 | + }); | ||
83 | + | ||
84 | + this.reset(); | ||
85 | + this.clacCoverSize(); | ||
86 | + }, | ||
87 | + watch: { | ||
88 | + pos() { | ||
89 | + this.timer && clearTimeout(this.timer); | ||
90 | + this.timer = setTimeout(this.resetViewList, 0); | ||
91 | + }, | ||
92 | + list(newList, oldList) { | ||
93 | + if (oldList.length > newList.length) { | ||
94 | + this.reset(); | ||
95 | + } | ||
96 | + | ||
97 | + this.clacCoverSize(); | ||
98 | + } | ||
99 | + }, | ||
100 | + computed: { | ||
101 | + listHeight() { | ||
102 | + return Math.max.apply(null, this.colsHeight); | ||
103 | + }, | ||
104 | + colWidth() { | ||
105 | + return this.$el.offsetWidth / this.cols; | ||
106 | + } | ||
107 | + }, | ||
108 | + methods: { | ||
109 | + clacCoverSize() { | ||
110 | + let nlist = []; | ||
111 | + | ||
112 | + for (let i = this.calcIndex; i < this.list.length; i++) { | ||
113 | + let item = this.list[i]; | ||
114 | + | ||
115 | + item.coverHeight = Math.floor(item.imageHeight / item.imageWidth * this.coverImageWidth); | ||
116 | + | ||
117 | + nlist.push(assign({_temporary: true}, item)); | ||
118 | + }; | ||
119 | + | ||
120 | + this.$emit('calced', nlist); | ||
121 | + }, | ||
122 | + calcCoverImgHeight(w, h) { | ||
123 | + return h / w * this.coverImageWidth; | ||
124 | + }, | ||
125 | + calcLayout() { | ||
126 | + let $item = this.$el.getElementsByClassName('wf-item-temp'); | ||
127 | + | ||
128 | + if (!$item || !$item.length) { | ||
129 | + return; | ||
130 | + } | ||
131 | + | ||
132 | + if (!this.loadedIndex || !this.colsHeight) { | ||
133 | + this.colsHeight = []; | ||
134 | + } | ||
135 | + | ||
136 | + for (let i = this.loadedIndex; i < this.list.length; i++) { | ||
137 | + let $elem = $item[i - this.loadedIndex]; | ||
138 | + | ||
139 | + if (!$elem) { | ||
140 | + return; | ||
141 | + } | ||
142 | + | ||
143 | + let height = $elem.offsetHeight; | ||
144 | + let top, left, leftPer; | ||
145 | + let item = this.list[i]; | ||
146 | + | ||
147 | + item.height = height; | ||
148 | + | ||
149 | + if (i < this.cols) { | ||
150 | + this.colsHeight[i] = height; | ||
151 | + top = 0 | ||
152 | + left = i * this.colWidth; | ||
153 | + leftPer = i * this.colWidthPer; | ||
154 | + } else { | ||
155 | + let minHeight = Math.min.apply(null, this.colsHeight); | ||
156 | + let minIndex = this.colsHeight.indexOf(minHeight); | ||
157 | + | ||
158 | + top = minHeight; | ||
159 | + left = minIndex * this.colWidth; | ||
160 | + leftPer = minIndex * this.colWidthPer; | ||
161 | + | ||
162 | + this.colsHeight[minIndex] = minHeight + height; | ||
163 | + } | ||
164 | + | ||
165 | + item.left = left; | ||
166 | + item.leftPer = leftPer; | ||
167 | + item.top = top; | ||
168 | + item.bottom = top + height; | ||
169 | + } | ||
170 | + | ||
171 | + this.loadedIndex = this.list.length; | ||
172 | + | ||
173 | + this.resetViewList(); | ||
174 | + }, | ||
175 | + setImgWidth() { | ||
176 | + let imgWidth = this.$el.offsetWidth / this.cols; | ||
177 | + let $item = this.$el.getElementsByClassName('wf-item'); | ||
178 | + | ||
179 | + if ($item && $item.length) { | ||
180 | + let _w = $item[0].offsetWidth; | ||
181 | + let $img = $item[0].getElementsByClassName('layer-image'); | ||
182 | + | ||
183 | + (_w > 0) && (imgWidth = _w); | ||
184 | + | ||
185 | + if ($img && $img.length) { | ||
186 | + _w = $img[0].offsetWidth; | ||
187 | + (_w > 0) && (imgWidth = _w); | ||
188 | + } | ||
189 | + } | ||
190 | + | ||
191 | + this.coverImageWidth = imgWidth; | ||
192 | + }, | ||
193 | + reset() { | ||
194 | + this.offsetTop = this.$el.offsetTop; | ||
195 | + this.clientHeight = document.body.clientHeight; | ||
196 | + this.colWidthPer = 100 / this.cols; | ||
197 | + this.loadedIndex = 0; | ||
198 | + this.calcIndex = 0; | ||
199 | + | ||
200 | + this.viewList = []; | ||
201 | + this.lastPos = 0; | ||
202 | + this.viewIndex = 0; | ||
203 | + | ||
204 | + this.setImgWidth(); | ||
205 | + }, | ||
206 | + resetViewList() { | ||
207 | + this.viewIndex = this.viewIndex || {}; | ||
208 | + | ||
209 | + let i, step; | ||
210 | + let startPos = this.pos - this.clientHeight * 2; | ||
211 | + let endPos = this.pos + this.clientHeight * 2; | ||
212 | + let list = []; | ||
213 | + let indexArr = []; | ||
214 | + | ||
215 | + if (this.pos < this.lastPos) { | ||
216 | + i = Math.min.apply(null, [(this.viewIndex['end'] || 0), this.list.length - 1]); | ||
217 | + step = -1; | ||
218 | + } else { | ||
219 | + i = Math.max.apply(null, [(this.viewIndex['start'] || 0), 0]); | ||
220 | + step = 1; | ||
221 | + } | ||
222 | + | ||
223 | + let loop = true; | ||
224 | + | ||
225 | + while (loop) | ||
226 | + { | ||
227 | + if (i < 0 || i >= this.list.length) { | ||
228 | + loop = false; | ||
229 | + continue; | ||
230 | + } | ||
231 | + | ||
232 | + let item = this.list[i]; | ||
233 | + | ||
234 | + if (item) { | ||
235 | + if (item.top > endPos - this.offsetTop) { | ||
236 | + if (step > 0) { | ||
237 | + loop = false; | ||
238 | + } | ||
239 | + } else if (item.bottom < startPos - this.offsetTop) { | ||
240 | + if (step < 0) { | ||
241 | + loop = false; | ||
242 | + } | ||
243 | + } else { | ||
244 | + indexArr.push(i); | ||
245 | + list.push(item); | ||
246 | + } | ||
247 | + } | ||
248 | + | ||
249 | + i += step; | ||
250 | + } | ||
251 | + | ||
252 | + if (!indexArr.length) { | ||
253 | + return; | ||
254 | + } | ||
255 | + | ||
256 | + indexArr = indexArr.sort(function(a, b) { | ||
257 | + return a - b; | ||
258 | + }); | ||
259 | + | ||
260 | + let viewIndex = { | ||
261 | + start: indexArr[0], | ||
262 | + end: indexArr[indexArr.length - 1] | ||
263 | + }; | ||
264 | + | ||
265 | + if (this.viewIndex.start !== viewIndex.start || this.viewIndex.end !== viewIndex.end) { | ||
266 | + this.viewList = list; | ||
267 | + this.lastPos = this.pos; | ||
268 | + this.viewIndex = viewIndex; | ||
269 | + } | ||
270 | + } | ||
271 | + } | ||
272 | +}; | ||
273 | +</script> | ||
274 | + | ||
275 | +<style lang="css"> | ||
276 | + .wf-list { | ||
277 | + margin: 0 20px; | ||
278 | + font-size: 0; | ||
279 | + position: relative; | ||
280 | + } | ||
281 | + | ||
282 | + .wf-item { | ||
283 | + padding: 10px; | ||
284 | + font-size: 24px; | ||
285 | + overflow: hidden; | ||
286 | + position: absolute; | ||
287 | + | ||
288 | + .wf-item-mid { | ||
289 | + border-radius: 4px; | ||
290 | + box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.15); | ||
291 | + overflow: hidden; | ||
292 | + } | ||
293 | + | ||
294 | + .layer-image { | ||
295 | + background-color: #f4f4f4; | ||
296 | + min-height: 100px; | ||
297 | + | ||
298 | + > img { | ||
299 | + width: 100%; | ||
300 | + height: 100%; | ||
301 | + display: block; | ||
302 | + } | ||
303 | + } | ||
304 | + | ||
305 | + .description { | ||
306 | + line-height: 1.5; | ||
307 | + padding: 10px 20px; | ||
308 | + } | ||
309 | + | ||
310 | + .attribution { | ||
311 | + display: flex; | ||
312 | + justify-content: space-between; | ||
313 | + padding: 20px; | ||
314 | + } | ||
315 | + | ||
316 | + .avatar { | ||
317 | + width: 60px; | ||
318 | + height: 60px; | ||
319 | + border-radius: 50%; | ||
320 | + display: inline-block; | ||
321 | + vertical-align: middle; | ||
322 | + overflow: hidden; | ||
323 | + | ||
324 | + > img { | ||
325 | + width: 100%; | ||
326 | + height: 100%; | ||
327 | + } | ||
328 | + } | ||
329 | + | ||
330 | + .name { | ||
331 | + display: inline-block; | ||
332 | + vertical-align: middle; | ||
333 | + } | ||
334 | + | ||
335 | + .fav { | ||
336 | + line-height: 60px; | ||
337 | + } | ||
338 | + } | ||
339 | + | ||
340 | + .wf-item-default, | ||
341 | + .wf-item-temp { | ||
342 | + opacity: 0; | ||
343 | + margin-left: -100%; | ||
344 | + } | ||
345 | +</style> |
@@ -41,4 +41,40 @@ export default { | @@ -41,4 +41,40 @@ export default { | ||
41 | 41 | ||
42 | return result; | 42 | return result; |
43 | }, | 43 | }, |
44 | + async autherBaseInfo(actions, {authorUid, authorType}) { | ||
45 | + const result = await this.$api.get('/api/grass/getGrassUserBaseInfo', { | ||
46 | + authorUid, | ||
47 | + authorType | ||
48 | + }); | ||
49 | + | ||
50 | + return result; | ||
51 | + }, | ||
52 | + async autherAritcleNum(actions, {authorUid, authorType}) { | ||
53 | + const result = await this.$api.get('/api/grass/getGrassPubAndFavorNum', { | ||
54 | + authorUid, | ||
55 | + authorType | ||
56 | + }); | ||
57 | + | ||
58 | + return result; | ||
59 | + }, | ||
60 | + async autherPubList(actions, {authorUid, authorType, page, lastedTime}) { | ||
61 | + const result = await this.$api.get('/api/grass/userPublishedArticleList', { | ||
62 | + authorUid, | ||
63 | + authorType, | ||
64 | + page, | ||
65 | + lastedTime | ||
66 | + }); | ||
67 | + | ||
68 | + return result; | ||
69 | + }, | ||
70 | + async autherFavList(actions, {authorUid, authorType, page, lastedTime}) { | ||
71 | + const result = await this.$api.get('/api/grass/userFavouriteArticleList', { | ||
72 | + authorUid, | ||
73 | + authorType, | ||
74 | + page, | ||
75 | + lastedTime | ||
76 | + }); | ||
77 | + | ||
78 | + return result; | ||
79 | + }, | ||
44 | }; | 80 | }; |
@@ -2,7 +2,10 @@ const URI_PACKAGE_ARTICLE = 'guang/service/v2/article/'; | @@ -2,7 +2,10 @@ const URI_PACKAGE_ARTICLE = 'guang/service/v2/article/'; | ||
2 | const URI_PACKAGE_AUTHOR = 'guang/service/v1/author/'; | 2 | const URI_PACKAGE_AUTHOR = 'guang/service/v1/author/'; |
3 | const URI_PACKAGE_PRAISE = 'guang/api/v1/article/'; | 3 | const URI_PACKAGE_PRAISE = 'guang/api/v1/article/'; |
4 | 4 | ||
5 | +const userPageApis = require('./api-map/userpage'); | ||
6 | + | ||
5 | module.exports = { | 7 | module.exports = { |
8 | + ...userPageApis, | ||
6 | '/api/grass/labelRealtedArticleDetail': { | 9 | '/api/grass/labelRealtedArticleDetail': { |
7 | api: 'app.grass.labelRealtedArticleDetail', | 10 | api: 'app.grass.labelRealtedArticleDetail', |
8 | cache: true, | 11 | cache: true, |
config/api-map/userpage.js
0 → 100644
1 | +module.exports = { | ||
2 | + '/api/grass/getGrassUserBaseInfo': { | ||
3 | + api: 'app.grass.getGrassUserBaseInfo', | ||
4 | + cache: true, | ||
5 | + params: { | ||
6 | + authorUid: {type: Number, require: true}, | ||
7 | + authorType: {type: Number, require: true} | ||
8 | + } | ||
9 | + }, | ||
10 | + '/api/grass/getGrassPubAndFavorNum': { | ||
11 | + api: 'app.grass.getGrassPubAndFavorNum', | ||
12 | + cache: true, | ||
13 | + params: { | ||
14 | + authorUid: {type: Number, require: true}, | ||
15 | + authorType: {type: Number, require: true} | ||
16 | + } | ||
17 | + }, | ||
18 | + '/api/grass/userPublishedArticleList': { | ||
19 | + api: 'app.grass.userPublishedArticleList', | ||
20 | + cache: true, | ||
21 | + params: { | ||
22 | + authorUid: {type: Number, require: true}, | ||
23 | + authorType: {type: Number, require: true}, | ||
24 | + page: {type: Number}, | ||
25 | + lastedTime: {type: Number} | ||
26 | + } | ||
27 | + }, | ||
28 | + '/api/grass/userFavouriteArticleList': { | ||
29 | + api: 'app.grass.userFavouriteArticleList', | ||
30 | + cache: true, | ||
31 | + params: { | ||
32 | + authorUid: {type: Number, require: true}, | ||
33 | + authorType: {type: Number, require: true}, | ||
34 | + page: {type: Number}, | ||
35 | + lastedTime: {type: Number} | ||
36 | + } | ||
37 | + }, | ||
38 | +} |
-
Please register or login to post a comment