Authored by 毕凯

Merge branch 'feature/guang2' into 'release/5.8'

逛需求



See merge request !625
... ... @@ -122,6 +122,8 @@ const _shareInfo = (id, getArticle) => {
*/
const index = (req, res, next) => {
let id = req.query.id || req.params[0] || req.params.id,
uid = req.user.uid,
udid = req.sessionID || require('yoho-md5')(req.ip) || 'yoho',
gender = req.query.gender ||
req.query.channel && typeLib.channels[req.query.channel] ||
req.cookies._Channel && channels[req.cookies._Channel] ||
... ... @@ -157,6 +159,12 @@ const index = (req, res, next) => {
co(function* () {
let detail = yield req.ctx(DetailModel).packageData(id, isApp, isWeixin, channel, isShare);
let commentsTotal = yield req.ctx(DetailModel).commentsTotal({article_id: id});
let praise = yield req.ctx(DetailModel).getArticlePraiseAndFavor({
uid: uid,
id: id,
udid: udid
});
let data = {
guangDetail: true,
guang: {}
... ... @@ -198,8 +206,11 @@ const index = (req, res, next) => {
id: _.get(detail, 'getArticle.id'),
title: detail.getArticle.article_title,
publishTime: detail.getArticle.publishTime,
pageView: detail.getArticle.pageViews,
content: []
pageView: _.get(praise, 'browseNum', 0),
content: [],
praise: _.get(praise, 'praiseNum', 0),
praiseHeadIco: _.get(praise, 'praiseHeadIco', []),
commentsTotal: commentsTotal
};
if (!detail.getArticleContent) {
return next();
... ... @@ -254,7 +265,8 @@ const index = (req, res, next) => {
wechatShare: true,
isWeixin: isWeixin,
localCss: true,
isShare: isShare
isShare: isShare,
id: id
}, data, parameter));
})().catch(next);
};
... ... @@ -287,6 +299,8 @@ const indexRedirect = (req, res, next) => {
*/
const mini = (req, res, next) => {
let id = req.query.id,
uid = req.user.uid,
udid = req.sessionID || require('yoho-md5')(req.ip) || 'yoho',
gender = req.query.gender || req.cookies._Channel && channels[req.cookies._Channel] || 1,
isApp = req.query.app_version || req.query.appVersion || false; // 标识是不是APP访问的
... ... @@ -302,6 +316,12 @@ const mini = (req, res, next) => {
co(function* () {
let detail = yield req.ctx(DetailModel).packageData(id, isApp);
let commentsTotal = yield req.ctx(DetailModel).commentsTotal({article_id: id});
let praise = yield req.ctx(DetailModel).getArticlePraiseAndFavor({
uid: uid,
id: id,
udid: udid
});
let data = {
guangEzine: true,
guang: {}
... ... @@ -317,8 +337,11 @@ const mini = (req, res, next) => {
guang.detail = {
title: detail.getArticle.article_title,
publishTime: detail.getArticle.publishTime,
pageView: detail.getArticle.pageViews,
content: []
pageView: _.get(praise, 'browseNum', 0),
content: [],
praise: _.get(praise, 'praiseNum', 0),
praiseHeadIco: _.get(praise, 'praiseHeadIco', []),
commentsTotal: commentsTotal
};
... ... @@ -349,7 +372,8 @@ const mini = (req, res, next) => {
page: 'info-index',
title: '逛',
gender: gender,
wechatShare: true
wechatShare: true,
id: id
}, data));
} else {
return next();
... ... @@ -423,9 +447,29 @@ const foryoho = (req, res, next) => {
})().catch(next);
};
/**
* 异步获取逛文章评论
* @param {*} req
* @param {*} res
* @param {*} next
*/
const getComments = (req, res, next) => {
req.ctx(DetailModel).comments({
article_id: req.query.article_id,
page: req.query.page
}).then(result => {
return res.render('info/comments', {
comments: result,
layout: false
});
}).catch(next);
};
module.exports = {
index,
mini,
foryoho,
indexRedirect
indexRedirect,
getComments
};
... ...
... ... @@ -11,7 +11,8 @@ const helpers = global.yoho.helpers;
const URI_PACKAGE_ARTICLE = 'guang/service/v2/article/';
const URI_PACKAGE_AUTHOR = 'guang/service/v1/author/';
const URI_PACKAGE_COMMENTS = 'guang/api/v1/comments/';
const URI_PACKAGE_PRAISE = 'guang/api/v1/article/';
class DetailModel extends global.yoho.BaseModel {
constructor(ctx) {
... ... @@ -348,6 +349,47 @@ class DetailModel extends global.yoho.BaseModel {
return _.get(result, 'data.product_list', []);
});
}
/**
* 获取文章评论列表
*/
comments(params) {
return serviceAPI.get(`${URI_PACKAGE_COMMENTS}getList`, {
article_id: params.article_id,
page: params.page,
limit: params.limit || 10
}).then(result => {
return _.get(result, 'data.list', []);
});
}
/**
* 获取评论数量
* @param {*} params
*/
commentsTotal(params) {
return serviceAPI.get(`${URI_PACKAGE_COMMENTS}getList`, {
article_id: params.article_id,
page: 1,
limit: 1
}).then(result => {
return _.get(result, 'data.total', 0);
});
}
/**
* 获取点赞相关数据
* @param {*} params
*/
getArticlePraiseAndFavor(params) {
return serviceAPI.get(`${URI_PACKAGE_PRAISE}getArticlePraiseAndFavor`, {
uid: params.uid,
id: params.id,
udid: params.udid
}).then(result => {
return _.get(result, 'data', {});
});
}
}
module.exports = DetailModel;
... ...
... ... @@ -133,7 +133,8 @@ class IndexModel extends global.yoho.BaseModel {
return api.all([
this._category(),
this._article(param)
this._article(param),
this._getTopArticles(param)
]).then(result => {
let type = param.type;
... ... @@ -204,11 +205,13 @@ class IndexModel extends global.yoho.BaseModel {
}
let infoList = _.get(result && result[2], 'data.list.artList', []);
if (result && result[1] && result[1].data && result[1].data.list && result[1].data.list.artList) {
let inf = [];
let infoList = result[1].data.list.artList;
infoList = _.concat(infoList, result[1].data.list.artList);
infoList.forEach(val => {
inf.push(guangProcess.formatArticle(val, true, false, true));
... ... @@ -321,6 +324,16 @@ class IndexModel extends global.yoho.BaseModel {
}
/**
* 获取置顶的文章
* @param {*} params
*/
_getTopArticles(params) {
return serviceAPI.get('guang/api/v6/article/getTopList', {
gender: params.gender
});
}
/**
* 逛分类
*/
_category() {
... ...
... ... @@ -59,6 +59,8 @@ router.get('/:id.html', detail.index); // 逛详情页(兼容 PC 跳转过来的
router.get('/info/mini', detail.mini); // 逛mini内容页
router.get('/info/foryoho', detail.foryoho); // 逛foryoho内容页
router.get('/info/getComments', detail.getComments); // 异步获取逛文章评论
router.get('/plustar', plustar.getListData); // 国际优选列表页
router.get('/plustar/brandinfo', plustar.getDetailData); // 国际优选详情页
router.post('/plustar/brandinfoAsync', plustar.getDetailDataAsync); // 国际优选详情页异步数据
... ...
{{#comments}}
<div class="comments-list clearfix">
<div class="avatar">
<img src="{{avator}}" alt="">
</div>
<div class="info-box">
<div class="info-top">
<div>
<span class="username">{{username}}</span>
<span class="info-right">
<span class="iconfont">&#xe601;</span>
<span>{{praiseNum}}</span>
</span>
</div>
<div class="time"><span>{{create_time}}</span></div>
</div>
<div class="info-bottom">{{#relayTo}}回复{{username}}{{/relayTo}}{{content}}</div>
</div>
</div>
{{/comments}}
\ No newline at end of file
... ...
<div class="guang-detail-page guang-page yoho-page {{#if guangDetail}}guang-detail{{/if}} {{#if guangEzine}}guang-ezine{{/if}}" id="guangDetail">
<div class="guang-detail-page guang-page yoho-page {{#if guangDetail}}guang-detail{{/if}} {{#if guangEzine}}guang-ezine{{/if}}" id="guangDetail" data-id={{id}}>
{{# guang}}
<div id="wrapper" >
<div id="scroller" class="{{channel}}">
... ... @@ -81,6 +81,10 @@
</div>
{{/if}}
{{#video}}
<video src="{{src}}" controls="controls" poster="{{cover_image}}">
{{/video}}
{{#if collocation}}
<div class="post-block collocation-block">
<ul class="thumb-container">
... ... @@ -200,6 +204,18 @@
{{> wx-footer}}
</div>
{{/ wxFooter}}
<div class="comments" id="comments">
<div class="comments-title clearfix">
<div class="avatar-list">
{{#each detail.praiseHeadIco}}
<img src="{{.}}" alt="">
{{/each}}
</div>
<div class="agree">{{detail.praise}}人点赞</div>
<div class="seenum"><span>{{detail.pageView}}</span>人看过</div>
</div>
<div class="comments-num"><span>评论{{detail.commentsTotal}}</span></div>
</div>
</div>
{{!-- wx-share --}}
... ...
... ... @@ -33,14 +33,25 @@
专题
<div class="info-tag special-topic"></div>
{{/ isSpecialTopic}}
{{# isVideo}}
视频
<div class="info-tag video"></div>
{{/ isVideo}}
{{# isShow}}
SHOW
<div class="info-tag show"></div>
{{/ isShow}}
</a>
{{/if}}
<a href="{{url}}">
<a class="img-box" href="{{url}}">
{{#if @first}}
<img src="{{image2 img q=60}}" alt="{{alt}}">
{{^}}
<img class="lazy" data-original="{{image2 img q=60}}" alt="{{alt}}">
{{/if}}
{{#if isVideo}}
<div class="play"></div>
{{/if}}
</a>
</div>
... ...
... ... @@ -11,8 +11,8 @@ const isProduction = process.env.NODE_ENV === 'production';
const isTest = process.env.NODE_ENV === 'test';
const domains = {
api: 'http://api.yoho.cn/',
service: 'http://service.yoho.cn/',
api: 'http://api-test3.yohops.com:9999/',
service: 'http://service-test3.yohops.com:9999/',
singleApi: 'http://api-test3.yohops.com:9999/',
global: 'http://global-test-soa.yohops.com:9999',
liveApi: 'http://testapi.live.yohops.com:9999/',
... ...
... ... @@ -24,6 +24,7 @@ function renderData(data) {
if (data && data.code === 200 && data.data) {
$('.guang-detail-page .page-view').text(data.data.browseNum || 0);
$('.guang-detail-page .comments .seenum span').text(data.data.browseNum || 0);
}
}
... ...
/*
* @Author: Targaryen
* @Date: 2017-05-25 14:36:33
* @Last Modified by: Targaryen
* @Last Modified time: 2017-06-02 10:51:56
*/
const $ = require('yoho-jquery');
const article_id = $('#guangDetail').data('id');
const $comments = $('#comments');
let page = 1;
let beforeScroll = document.body.scrollTop; // 滚动前位置记录
let onLoading = false; // 是否正在加载
let loadingEnd = false;
/**
* 异步加载评论
*/
const getComments = () => {
if (loadingEnd) {
return false;
}
if (!onLoading) {
onLoading = true;
} else {
return false;
}
$.ajax({
type: 'get',
url: '//guang.m.yohobuy.com/guang/info/getComments',
data: {
article_id: article_id,
page: page++
},
success: function(result) {
let noResult = !result || result.length < 1;
if (noResult) {
loadingEnd = true;
return false;
}
$comments.append(result);
onLoading = false;
}
});
};
/**
* 当scroll到1/2$goodsContainer高度后继续请求下一页数据
*/
const scrollHandler = function() {
if ($(window).scrollTop() > $('#guangDetail').height() * 0.6) {
getComments();
}
};
/**
* 滚动加载
*/
$(window).scroll(function() {
setTimeout(function() {
let afterScroll = document.body.scrollTop;
if (afterScroll - beforeScroll > 0) {
window.requestAnimationFrame(scrollHandler);
beforeScroll = afterScroll;
} else {
return false;
}
}, 5);
});
getComments();
... ...
... ... @@ -29,6 +29,7 @@ require('common');
require('plugin/wx-share')();
require('./detail-dynamic');
require('./detail/guang-cart');
require('./detail/guang-comments');
let CollactionBlock = require('./collocation-block');
... ... @@ -51,26 +52,6 @@ function initIscroll() {
hH = $yohoHeader.outerHeight();
}
/*
myScroll = new IScroll('#wrapper', {
probeType: 3,
mouseWheel: true,
click: true
});
document.addEventListener('touchmove', function(e) {
e.preventDefault();
}, false);
if (!hasCollocationBlock) {
myScroll.on('scroll', function() {
$scroller.trigger('scroll');
});
return;
}
*/
winH = $(window).height() - hH;
fixedThumbDom = $fixedThumbContainer[0];
... ... @@ -118,6 +99,18 @@ function initIscroll() {
}
}
});
// 评论滚动加载
// setTimeout(function() {
// let afterScroll = document.body.scrollTop;
// if (afterScroll - beforeScroll > 0) {
// window.requestAnimationFrame(scrollHandler);
// beforeScroll = afterScroll;
// } else {
// return false;
// }
// }, 5);
}
/**
... ... @@ -134,18 +127,6 @@ $relatedRecoMore.on('touchstart', function(e) {
}
});
/*
// window onload 后重新refresh iscroll
window.onload = function() {
myScroll && myScroll.refresh();
};
// 图片加载完成之后重新 refresh iscroll
$('img').on('load', function() {
myScroll && myScroll.refresh();
});
*/
// 微信导航
$('.nav-btn').on('touchstart', function() {
$sideNav.css('pointer-events', 'none');
... ... @@ -300,11 +281,6 @@ $('.wei-share').on('touchend', function(e) {
}
lazyLoad($('.lazy'));
// title mlellipsis
// $('.info-list .title, .one-good .reco-name').each(function() {
// this.mlellipsis(2);
// });
// offset.left约等于marginLeft的值则表示介绍被换行,则清除intro的paddingTop让其更靠近头像和作者名
if ($authorIntro.offset() && (parseInt($authorIntro.offset().left, 10) ===
parseInt($authorIntro.css('margin-left'), 10))) {
... ... @@ -318,8 +294,6 @@ $('.wei-share').on('touchend', function(e) {
$('#float-layer-close').on('touchend', function() {
let appClose = window.cookie('_float-layer-app-close') || '0';
// window.setCookie('_float-layer-app-close', 1);
if (parseInt(appClose, 10) === 0) {
setCookie('_float-layer-app-close', 1, {expires: -1});
... ... @@ -351,14 +325,11 @@ $('.wei-share').on('touchend', function(e) {
});
if (typeof window.cookie === 'function' && parseInt(window.cookie('_float-layer-app-close'), 10) !== 2) {
// $('#float-layer-app').show();
$('.down-bottom').show();
} else {
// $('#float-layer-app').hide();
$('.down-bottom').hide();
}
}
initIscroll();
}());
... ...
... ... @@ -712,6 +712,7 @@ $focus-size: 42px;
margin: 30px 0;
overflow-x: scroll;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
}
.recommend-products-box > .recommend-products-content {
... ... @@ -748,6 +749,10 @@ $focus-size: 42px;
padding: 6px;
}
}
video {
width: 100%;
}
}
.guang-detail-page.menu-open {
... ...
... ... @@ -40,6 +40,16 @@
width: 100%;
min-height: 400px;
}
.play {
position: absolute;
width: 140px;
height: 140px;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
background-image: url("/guang/play-btn.png");
}
}
.info-match {
... ... @@ -84,6 +94,14 @@
&.topic {
background-image: url("/guang/info/topic.png");
}
&.video {
background-image: url("/guang/info/video.png");
}
&.show {
background-image: url("/guang/info/show.png");
}
}
.info-deps {
... ...
... ... @@ -2,7 +2,7 @@
* @Author: Targaryen
* @Date: 2017-05-03 14:08:52
* @Last Modified by: Targaryen
* @Last Modified time: 2017-05-15 19:22:38
* @Last Modified time: 2017-05-27 14:53:10
*/
.guang-list-page {
.product-list-box {
... ... @@ -11,6 +11,7 @@
padding: 0 20px;
overflow-x: scroll;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
}
.product-list {
... ...
/*
* @Author: Targaryen
* @Date: 2017-05-25 15:49:46
* @Last Modified by: Targaryen
* @Last Modified time: 2017-06-02 10:43:21
*/
.guang-detail-page .comments {
margin-top: 30px;
background-color: #fff;
.comments-title {
color: #444;
padding: 30px;
border-bottom: 1px solid #b0b0b0;
line-height: 70px;
.avatar-list {
float: left;
margin-right: 30px;
img {
width: 70px;
height: 70px;
border-radius: 35px;
margin-left: -35px;
float: left;
border: 2px solid #fff;
}
img:first-child {
margin-left: 0;
}
}
.agree {
float: left;
}
.seenum {
float: right;
}
}
.comments-num {
padding: 0 30px;
height: 50px;
line-height: 50px;
}
.comments-num > span {
color: #b0b0b0;
}
.comments-list {
padding-bottom: 40px;
margin: 30px;
border-bottom: 1px solid #b0b0b0;
&:last-child {
border-bottom: none;
}
.avatar {
float: left;
width: 70px;
overflow: hidden;
margin-right: 30px;
}
.avatar > img {
width: 70px;
height: 70px;
border-radius: 35px;
}
.info-box {
float: left;
width: 480px;
overflow: hidden;
}
.info-top {
.username {
font-size: 26px;
font-weight: 700;
color: #444;
}
.info-right {
float: right;
color: #b0b0b0;
}
.time {
color: #b0b0b0;
padding: 5px 0;
}
}
.info-bottom {
color: #444;
}
}
}
... ...
... ... @@ -6,3 +6,4 @@
@import "detail";
@import "tvls";
@import "channel/side-nav";
@import "./detail/comments";
... ...
... ... @@ -33,7 +33,7 @@ const transHttpsUrl = (url) => {
* @return {[strng]}
*/
const getFilterUrl = (url) => {
url = url.replace('.m.yohobuy.com', global.yoho.config.subDomains.host)
url = url && url.replace('.m.yohobuy.com', global.yoho.config.subDomains.host)
.replace('www.yohobuy.com', global.yoho.config.siteUrl);
const whiteDomains = ['m.yohobuy.com', 'cdn.yoho.cn/myohobuy'];
... ... @@ -43,15 +43,16 @@ const getFilterUrl = (url) => {
'huodong.m.yohobuy.com',
'/home/orders/pay'];
if (whiteDomains.every(item => url.includes(item)) &&
if (whiteDomains.every(item => url && url.includes(item)) &&
blackDomains.every(item => !url.includes(item))) {
url = url.replace('http://', '//');
}
if (url.includes('feature.yoho.cn')) {
if (url && url.includes('feature.yoho.cn')) {
url = transHttpsUrl(url);
}
if (url.includes('openby:yohobuy=')) {
if (url && url.includes('openby:yohobuy=')) {
let filters = ['openby:yohobuy=', '&', '?'];
filters.forEach(item => {
... ... @@ -162,6 +163,12 @@ const formatArticle = (articleData, showTag, isApp, showAuthor, uid) => {
case '19': // 专题
result.isSpecialTopic = true;
break;
case '9999': // 视频
result.isVideo = true;
break;
case '24': // Show
result.isShow = true;
break;
default:
break;
}
... ... @@ -235,11 +242,16 @@ const processArticleDetail = (articleContent, isApp, gender, isWeixin, isqq, isW
if (_.get(value, 'singleImage.data.length', false)) {
let tagList = _.get(value, 'singleImage.data[0].tagList', []);
if (tagList.length > 0) {
_.forEach(tagList, (tag, tagIndex) => {
// 链接
tagList[tagIndex].href = '//m.yohobuy.com/product/' + tag.product_skn + '.html';
if (tag.is_global === 'Y') {
tagList[tagIndex].href = '//m.yohobuy.com/product/global/' + tag.product_skn + '.html';
} else {
tagList[tagIndex].href = '//m.yohobuy.com/product/' + tag.product_skn + '.html';
}
tagList[tagIndex].isApp = isApp;
});
}
... ... @@ -362,6 +374,18 @@ const processArticleDetail = (articleContent, isApp, gender, isWeixin, isqq, isW
recommendProducts: _.get(value, 'recommend_products.data', [])
});
}
// 视频
if (_.get(value, 'video', false)) {
let video = {
src: _.get(value, 'video.data.src', ''),
cover_image: _.get(value, 'video.data.cover_image', '')
};
finalDetail.push({
video: video
});
}
});
return {
... ...