Authored by 郝肖肖

'news'

/**
* guang controller
* @author: lcy<chuanyang.liu@yoho.cn>
* @date: 2016/08/31
*/
'use strict';
const newsService = require('../models/news-service');
/**
* 首页文章列表 类型列表
*/
exports.index = (req, res, next) => {
let channel = req.yoho.channel;
req.ctx(newsService).getIndexList(channel, req.query).then(result => {
if (result.msgs.length <= 0) {
res.set('Cache-Control', 'no-cache');
}
return res.render('news-index', Object.assign({
title: '新闻 | ' + (res.locals.title || ''),
module: 'news',
page: 'index'
}, result));
}).catch(next);
};
/**
* 文章详情
*/
exports.detail = (req, res, next) => {
let channel = req.yoho.channel;
let id = req.params[0] || 0;
let cid = req.params[1] || 0;
let query = {
channel: channel,
id: id,
cid: cid,
};
if (!id || !cid) {
return next();
}
req.ctx(newsService).detail(channel, query).then(result => {
return res.render('news-detail', Object.assign({
module: 'news',
page: 'detail'
}, result));
}).catch(next);
};
... ...
/**
* news
* @author: xiaoxiao<xiaoxiao.hao@yoho.cn>
* @date: 2017/10/13
*/
'use strict';
var express = require('express'),
path = require('path'),
hbsEvent = require('../../config/hbsevent');
var app = express();
// set view engin
var doraemon = path.join(__dirname, '../../doraemon/views'); // parent view root
app.disable('x-powered-by');
app.on('mount', function(parent) {
delete parent.locals.settings; // 不继承父 App 的设置
Object.assign(app.locals, parent.locals);
});
app.use(global.yoho.hbs({
extname: '.hbs',
defaultLayout: 'layout',
layoutsDir: doraemon,
partialsDir: [path.join(__dirname, 'views/partial')],
views: path.join(__dirname, 'views/action'),
helpers: global.yoho.helpers,
cb: hbsEvent.cb
}));
// router
app.use(require('./router'));
module.exports = app;
... ...
'use strict';
module.exports = class extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
}
getPolymerizationList(params) {
return this.get({
url: 'yohonow/api/page/getPolymerizationList',
data: params,
param: {
cache: true
},
api: global.yoho.YohoNowApi
});
}
getContentDetail(params) {
return this.get({
url: 'yohoboyins/v5/channel/getContentDetail',
data: {parameters: JSON.stringify(params)},
param: {
cache: true
},
api: global.yoho.YohoNowApi
});
}
/**
* 推荐文章
*/
getRecoArticles(params) {
return this.get({
url: 'guang/api/v2/article/getArticleByViewsNum',
data: params,
param: {
cache: true
},
api: global.yoho.ServiceAPI
});
}
/**
* 获取广告数据
* @param {String} channelType 传入频道页类型,值可以是: boys, girls, kids, lifestyle
* @return {Object}
*/
getAds(params) {
if (params.isAdDegrade) {
return Promise.resolve({});
}
return this.get({
url: 'operations/api/v5/resource/get',
data: params,
param: {
cache: true
},
api: global.yoho.ServiceAPI
});
}
};
... ...
'use strict';
const _ = require('lodash');
const helpers = global.yoho.helpers;
const NewsAPi = require('./news-api');
const utils = require('./utils');
const moment = require('moment');
// 逛 ads code
const ADS_CODE = {
boys: '41777aa7ac86347692c5aa0d394b2f59',
girls: '722253573823ebb994e313e71b0a4fb9',
lifestyle: '02568b6042510e4be739cc688dc7d6ae',
kids: '1ffdd6ea22c58af52ee6408cd353c2d5'
};
module.exports = class extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
}
_formatArticle(rdata, params) {
let list = _.get(rdata, 'data.content', []);
let total = _.get(rdata, 'data.total', 0);
let lresult = {};
let width = 360;
let height = 240;
let result = _.map(list, (articleData) => {
articleData.image += '?imageView2/{mode}/w/{width}/h/{height}';
lresult = {
id: articleData.id,
classification: _.get(articleData, 'min_category_name', '') || _.get(articleData, 'category_name', ''),
url: helpers.urlFormat(`/news/${articleData.id}_${articleData.cid}.html`),
img: helpers.image(articleData.image, width, height, 1),
title: articleData.title,
pTime: articleData.update_time && moment(articleData.update_time * 1000).format('YYYY年MM月DD HH:mm'),
pView: articleData.views_num,
content: articleData.summary,
isVideo: articleData.videoUrl ? true : false
};
return lresult;
});
return {msgs: result, totalCount: total};
}
getIndexList(channel, param) {
let newsAPi = new NewsAPi(this.ctx);
let params = {
type: 'wechat',
atype: param.atype || 'yohogroup',
limit: 20,
page: param.page || 1
};
let apiMethod = [
newsAPi.getPolymerizationList(Object.assign({}, params, {id: param.atype || 'yohogroup'})),
];
return Promise.all(apiMethod).then(result => {
let responseData = {};
// 列表数据
Object.assign(responseData, this._formatArticle(result[3], params));
return responseData;
});
}
_formatDetail(rdata) {
let contents = _.get(rdata, 'data.contents', {});
let header = {
title: contents.title,
summary: contents.summary,
tag: contents.tag,
time: contents.update_time && moment(contents.update_time * 1000).format('YYYY年MM月DD HH:mm'),
};
let content = utils.filterPhtml(contents.content, [
'阅读原文',
'点击这里',
'点这里'
]);
return {header: header, content: utils.filterAhtml(content)};
}
detail(channel, param) {
let params = {
id: param.id,
cid: param.cid
};
let newsAPi = new NewsAPi(this.ctx);
let apiMethod = [
newsAPi.getContentDetail(params)
];
return Promise.all(apiMethod).then(result => {
let responseData = {};
// 详情页数据
Object.assign(responseData, this._formatDetail(result[3], params));
// seo
let title = _.get(responseData, 'header.title', '新闻详情页');
let keywords = [];
let tags = _.compact(_.get(responseData, 'header.tag', []).map(el => {
return el.tag_name;
}));
keywords.push(title, tags.slice(0, 3).join('、'), 'YOHO!BUY有货');
Object.assign(responseData, {
title: `${title} | YOHO!BUY有货`,
keywords: keywords.join('、'),
description: _.get(responseData, 'header.summary', _.get(this.ctx, 'res.locals.description'))
});
return responseData;
});
}
};
... ...
'use strict';
const _ = require('lodash');
const cheerio = require('cheerio');
const util = {
// 过滤指定字符的p标签
filterPhtml: (html, filters) => {
if (!html) {
return html;
}
let $ = cheerio.load(html, {decodeEntities: false});
_.each($('p'), (item) => {
let ele = $(item);
let phtml = ele.html();
_.each(filters, ft => {
if (phtml.indexOf(ft) >= 0) {
ele.remove();
}
});
});
return $.html();
},
// 过滤 a标签连接和删除html标签中的script和link脚本
filterAhtml: (html) => {
if (!html) {
return html;
}
let $ = cheerio.load(html, {decodeEntities: false});
$('a').attr('href', 'javascript:void(0);').css({cursor: 'text'});// eslint-disable-line
$('script,link').remove();
return $.html();
}
};
module.exports = util;
... ...
/**
* news
* @author: xiaoxiao<xiaoxiao.hao@yoho.cn>
* @date: 2017/10/13
*/
'use strict';
const router = require('express').Router(); // eslint-disable-line
const cRoot = './controllers';
const newsController = require(`${cRoot}/index`);
router.get(['/', '/index/index'], newsController.index);
router.get(/\/([\d]+)_([\d]+).html/, newsController.detail);
// ajax
module.exports = router;
... ...
<div class="news-detail-page news-page yoho-page clearfix">
{{> common/path-nav}}
<div class="left-side detail-body" data-id="{{id}}">
{{# header}}
<h1 class="detail-title">{{title}}</h1>
<div class="article-info clearfix">
{{#if authorUrl}}
<div class="article-author">
<div class="author-avatar">
<a href="{{authorUrl}}" target="_blank">
<img src="{{image2 avatar}}">
</a>
</div>
</div>
<div class="author-info">
<a class="author-name" href="{{authorUrl}}">{{name}}</a>
</div>
{{/if}}
<div class="article-status clearfix">
{{#if time}}
<span class="article-time">
<i class="iconfont">&#xe625;</i>
{{time}}
</span>
{{/if}}
{{#if click}}
<span class="article-click">点击:<em>{{click}}</em></span>
{{/if}}
{{#if commentNum}}
<a href="#comment-info" id="article-comment" class="article-comment"><em class="comment-num">{{commentNum}}</em>条评论</a>
{{/if}}
</div>
</div>
{{/ header}}
<div class="article-main">
{{{content}}}
</div>
</div>
<div class="right-side detail-side">
{{> news-right-side}}
</div>
</div>
... ...
<div class="news-list-page news-page yoho-page" id="guangList">
{{# msgs}}
<div id="info-list" class="info-list-container">
{{# infos}}
<div class="info-list{{^show}} hide{{/show}}">
{{# info}}
{{> index/info}}
{{/ info}}
</div>
{{/ infos}}
</div>
<div id="load-more-info" class="load-more-info">
<div class="loading status hide">
正在加载...
</div>
<span class="no-more status">没有更多啦</span>
</div>
{{/ msgs}}
</div>
{{> footer-tab}}
... ...
<div class="guang-info" data-id="{{id}}">
{{# author}}
<a class="info-author clearfix"{{#if url}} href="{{url}}"{{/if}}>
<img class="lazy avatar" data-original="{{image2 avatar mode=2 q=60}}">
<span class="name">{{name}}</span>
{{#if minCategory}}
<span class="min-tag">#{{minCategory}}</span>
{{/if}}
</a>
{{/ author}}
<div class="info-img">
{{#if showTags}}
<a href="javascript:;" class="info-match hide">
{{# isTip}}
小贴士
<div class="info-tag tip"></div>
{{/ isTip}}
{{# isCollocation}}
搭配
<div class="info-tag collocation"></div>
{{/ isCollocation}}
{{# isFashionMan}}
潮人
<div class="info-tag fashion-man"></div>
{{/ isFashionMan}}
{{# isFashionGood}}
潮品
<div class="info-tag fashion-good"></div>
{{/ isFashionGood}}
{{# isTopic}}
话题
<div class="info-tag topic"></div>
{{/ isTopic}}
{{# isSpecialTopic}}
专题
<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 class="img-box"{{#unless isShow}} href="{{url}}"{{/unless}}>
{{#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>
<div class="info-deps">
<a class="info-title-container"{{#unless isShow}} href="{{url}}"{{/unless}}>
<div class="info-title">{{#if top}}<span class="top-tag">置顶</span>{{/if}}{{title}}</div>
</a>
<p class="info-text">{{text}}</p>
{{> index/tvls}}
</div>
{{#unless @root.isApp}}
{{#if productList}}
<div class="product-list-box">
<ul class="product-list">
{{#productList}}
{{> index/product-list}}
{{/productList}}
</ul>
</div>
{{/if}}
{{/unless}}
</div>
... ...
<li class="goods-box">
<div class="goods-img">
<a href="{{href}}">
<img class="lazy" data-original="{{image2 pic_url w=106 h=138}}" />
</a>
</div>
<div class="goods-info">
<a href="{{href}}">
<p class="title">{{product_name}}</p>
<p class="price">¥{{price}}</p>
</a>
</div>
</li>
\ No newline at end of file
... ...
<div class="time-view-like-share clearfix">
<i class="iconfont">&#xe603;</i>
{{publishTime}}&nbsp;&nbsp;&nbsp;&nbsp;
<i class="iconfont">&#xe602;</i>
<span class="page-view">{{pageView}}</span>
<div class="like-share-container">
{{#like}}
<i class="iconfont like-btn{{#isLiked}} like{{/isLiked}}">&#xe601;</i>
<span class="like-count">{{count}}</span>
{{/ like}}
{{# collect}}
<i class="iconfont collect-btn{{#isCollected}} collected{{/isCollected}}">&#xe605;</i>
{{/ collect}}
{{# share}}
<a href="{{.}}" class="iconfont share-btn">&#xe600;</a>
{{/ share}}
</div>
</div>
\ No newline at end of file
... ...
... ... @@ -19,7 +19,8 @@ const domains = {
imCs: 'http://im.yohobuy.com/api',
platformApi: 'http://192.168.102.48:8088/',
store: 'http://192.168.102.47:8080/portal-gateway/wechat/',
extstore: 'http://extstore-test1.yohops.com'
extstore: 'http://extstore-test1.yohops.com',
yohoNowApi: 'http://yohonow-test.yohops.com:9999/',
};
module.exports = {
... ... @@ -144,7 +145,8 @@ if (isProduction) {
imSocket: 'wss://imsocket.yohobuy.com:443',
imCs: 'https://imhttp.yohobuy.com/api',
platformApi: 'http://api.platform.yohoops.org',
extstore: 'http://extstore.yohobuy.com'
extstore: 'http://extstore.yohobuy.com',
yohoNowApi: 'http://new.yohoboys.com/',
},
memcache: {
master: ['memcache1.yohoops.org:12111', 'memcache2.yohoops.org:12111', 'memcache3.yohoops.org:12111'],
... ... @@ -220,7 +222,8 @@ if (isProduction) {
imSocket: process.env.TEST_IM_SOCKET || 'ws://socket.yohobuy.com:10240',
imCs: process.env.TEST_IM_CS || 'http://im.yohobuy.com/api',
platformApi: 'http://192.168.102.48:8088/',
extstore: 'http://extstore-test1.yohops.com'
extstore: 'http://extstore-test1.yohops.com',
yohoNowApi: process.env.YOHO_NOW_API || 'http://yohonow-test.yohops.com:9999/',
},
memcache: {
master: ['127.0.0.1:12111'],
... ...
... ... @@ -16,6 +16,7 @@ module.exports = app => {
// 业务模块
app.use('/product', require('./apps/product'));
app.use('/guang', require('./apps/guang'));
app.use('/news', require('./apps/news'));
app.use('/activity', require('./apps/activity'));
app.use('/cart', require('./apps/cart'));
... ...