Authored by 郭成尧

merge-master

... ... @@ -23,7 +23,9 @@ exports.index = (req, res, next) => {
module: 'activity',
page: 'coupon-floor',
wechatShare: true,
title: '领券中心',
title: '有货优惠券_有货现金优惠券,全场券,品类券,品牌券_领券频道-Yoho!Buy有货',
keywords: '有货优惠券,有货现金优惠券,全场券,品类券,品牌券',
description: 'Yoho!Buy有货官网领券频道,提供有货优惠券,有货现金优惠券,有货全场券,有货品类券,品牌券免费领取,让你做网购达人,省钱又省心!',
pageHeader: headerModel.setNav({
navTitle: '领券中心'
}),
... ...
... ... @@ -22,9 +22,9 @@
style="{{#if param.bgcolor}}background-color:{{param.bgcolor}}{{/if}}">
{{#if param.bgimg}}
{{#isLazyLoad type @index}}
<img class="lazy" data-original="{{image2 param.bgimg q=75}}">
<img class="lazy" data-original="{{imageslim param.bgimg}}">
{{else}}
<img src="{{image2 param.bgimg q=75}}">
<img src="{{imageslim param.bgimg}}">
{{/isLazyLoad}}
{{/if}}
{{#component}}
... ... @@ -34,7 +34,7 @@
{{#if modalImg}}
<div class="modal">
<span class="modal-close"></span>
<img class="modal-img lazy" data-original="{{image2 modalImg q=75}}">
<img class="modal-img lazy" data-original="{{imageslim modalImg}}">
</div>
{{/if}}
{{/isEqualOr}}
... ... @@ -66,7 +66,7 @@
<div class="swiper-wrapper">
{{#list}}
<div class="swiper-slide" style="{{styleFormat this percent=1}}">
<img src="{{image2 src q=75}}">
<img src="{{imageslim src}}">
<a class="anchor" href="{{#if link}}{{link}}{{else}}javascript:void(0);{{/if}}" fp="{{getAnalysis ../../this @index}}"></a>
</div>
{{/list}}
... ... @@ -88,7 +88,7 @@
{{#isEqualOr type 'productGroup'}}
{{! 商品池}}
<div class="product-container item{{numOfOneRow}}" {{#if proBgImg}}style="background:url({{image2 proBgImg q=75}}) repeat;background-size:100%;"{{/if}}>
<div class="product-container item{{numOfOneRow}}" {{#if proBgImg}}style="background:url({{imageslim proBgImg}}) repeat;background-size:100%;"{{/if}}>
<div class="product-source" condition='{{stringify searchCondition}}' fp="{{getAnalysis ../this @index}}"
{{#unless defaultPros.length}}
{{#if searchCondition.item}}
... ... @@ -103,9 +103,9 @@
<div class="feature-product-info {{#if ../searchCondition}}novisible{{/if}}">
<a class="first-part product-detail" href='{{producturl}}'>
<div class="product-detail-imgbox">
{{#if ../lefTopImg}}<img class="leftopimg lazy" data-original="{{image2 ../lefTopImg q=75}}">{{/if}}
{{#if ../rigTopImg}}<img class="rigtopimg lazy" data-original="{{image2 ../rigTopImg q=75}}">{{/if}}
<img class="product-detail-img lazy" data-original="{{image2 productimg q=75}}">
{{#if ../lefTopImg}}<img class="leftopimg lazy" data-original="{{imageslim ../lefTopImg}}">{{/if}}
{{#if ../rigTopImg}}<img class="rigtopimg lazy" data-original="{{imageslim ../rigTopImg}}">{{/if}}
<img class="product-detail-img lazy" data-original="{{imageslim productimg}}">
</div>
{{#isEqualOr ../showPrdName '1'}}<p class="product-name">{{productname}}</p>{{/isEqualOr}}
<div class="product-detail-text">
... ... @@ -128,7 +128,7 @@
<div class="brand-div">
<span class="brand-name"{{#if ../fontColor}}style="color:{{../fontColor}};"{{/if}}>{{brandname}}</span>
</div>
<img class="brand-img lazy" data-original="{{image2 ../brandImg q=75}}">
<img class="brand-img lazy" data-original="{{imageslim ../brandImg}}">
</a>
{{/if}}
</div>
... ... @@ -137,8 +137,8 @@
<div class="feature-product-info novisible">
<a class="first-part product-detail" href=''>
<div class="product-detail-imgbox">
{{#if lefTopImg}}<img class="leftopimg" src="{{image2 lefTopImg q=75}}">{{/if}}
{{#if rigTopImg}}<img class="rigtopimg" src="{{image2 rigTopImg q=75}}">{{/if}}
{{#if lefTopImg}}<img class="leftopimg" src="{{imageslim lefTopImg}}">{{/if}}
{{#if rigTopImg}}<img class="rigtopimg" src="{{imageslim rigTopImg}}">{{/if}}
<img class="product-detail-img" src="">
</div>
{{#isEqualOr showPrdName '1'}}<p class="product-name"></p>{{/isEqualOr}}
... ... @@ -161,7 +161,7 @@
<div class="brand-div">
<span class="brand-name" {{#if fontColor}}style="color:{{fontColor}};"{{/if}}></span>
</div>
<img class="brand-img" src="{{image2 brandImg q=75}}">
<img class="brand-img" src="{{imageslim brandImg}}">
</a>
{{/if}}
</div>
... ...
... ... @@ -251,7 +251,6 @@ const index = (req, res, next) => {
console.log(data);
res.render('info/index', Object.assign({
page: 'info-index',
title: '逛',
gender: gender,
wechatShare: true,
isWeixin: isWeixin,
... ...
... ... @@ -67,7 +67,9 @@ const editor = (req, res, next) => {
res.render('index/list', Object.assign({
page: 'index-editor',
title: title,
title: `潮流编辑${authorData.data.name}|YOHO!BUY有货`,
keywords: `潮流编辑${authorData.data.name}`,
description: `YOHO!BUY有货潮流编辑${authorData.data.name}!`,
guangList: true,
gender: gender,
guang: {
... ... @@ -193,7 +195,9 @@ const index = (req, res, next) => {
let responseData = {
module: 'guang',
page: 'index',
title: '逛 | Yoho!Buy有货 | 潮流购物逛不停',
title: '逛|逛潮流,逛购物,官方授权正品潮流购物中心|YOHO!BUY有货',
keywords: '逛,逛潮流,逛购物',
description: 'YOHO!BUY有货逛频道,来YOHO!玩潮流!潮搭大解析!年轻人潮流购物中心,中国潮流购物风向标,吴亦凡重磅代言!YOHO!BUY有货100%正品保证,支持货到付款。',
showFooterTab: footerModel.getUrlData('guang')
};
... ... @@ -238,7 +242,9 @@ const tag = (req, res, next) => {
pageHeader: headerData,
module: 'guang',
page: 'index-editor',
title: tagTitle + ' | Yoho!Buy有货 | 潮流购物逛不停'
title: tagTitle + ' | Yoho!Buy有货 | 潮流购物逛不停',
keywords: tagTitle,
description: 'YOHO!BUY有货潮流' + tagTitle + '!'
};
let param = {
... ...
... ... @@ -12,6 +12,7 @@ const star = require(cRoot + '/star');
const homeController = require(`${cRoot}/index`);
const plusstar = require(cRoot + '/plusstar');
const rewrite = require('../../doraemon/middleware/rewrite');
const mip = require('../../doraemon/middleware/mip');
const index = require(cRoot + '/index');
const opt = require(cRoot + '/opt');
... ... @@ -52,7 +53,7 @@ router.post('/opt/collectArticle', opt.collectArticle); // 资讯文章收藏 (H
router.post('/opt/favoriteBrand', opt.favoriteBrand); // 品牌收藏
router.get('/info/index', rewrite.channel, detail.indexRedirect); // 逛详情页
router.get(/^\/info\/(.*?)\.html/, rewrite.resolve, detail.index); // 逛详情页 SEO优化
router.get(/^\/info\/(.*?)\.html/, rewrite.resolve, mip, detail.index); // 逛详情页 SEO优化
router.get('/:id.html', detail.index); // 逛详情页(兼容 PC 跳转过来的链接)
router.get('/info/mini', detail.mini); // 逛mini内容页
... ...
'use strict';
const css = require('../css');
// const mipUtils = require('../mip-utils');
const helpers = global.yoho.helpers;
const _ = require('lodash');
const co = require('bluebird').coroutine;
const stringProcess = require(`${global.utils}/string-process`);
const guangProcess = require(`${global.utils}/guang-process`);
const mRoot = '../models';
const DetailModel = require(`${mRoot}/guang`);
const typeLib = require('../../../config/type-lib');
const channels = {
boys: 1,
girl: 2,
kids: 3,
lifestyle: 4
};
// const testStr = '';
/**
* [处理品牌数据]
* @param {[array]} getBrand [品牌原数据]
*/
const _relatedBrand = (getBrand, isApp) => {
let relatedBrand = getBrand;
relatedBrand.forEach(brand => {
brand.thumb = brand.thumb.replace('http://', '//');
if (isApp) {
brand.url = brand.url + '?openby:yohobuy={"action":"go.brand","params":{"brand_id":"' + brand.id + '"}}';
}
});
return relatedBrand;
};
/**
* [处理标签数据]
* @param {[array]} tags [标签原数据]
* @param {[Boolean]} isApp [是否app]
*/
const _relatedTag = (tags, isApp) => {
let relatedTag = [];
let tagUrl;
tags.forEach(value => {
tagUrl = helpers.urlFormat('/tags/index', {query: value.name}, 'guang');
if (!isApp) {
value.url = tagUrl;
} else {
if (value.url.indexOf('openby') >= 0) {
value.url = value.url;
} else {
value.url = tagUrl + '&openby:yohobuy={"action":"go.h5","params":{"query":"' + value.name + '","type":0,"title":"' + value.name + '","url":"http://guang.m.yohobuy.com/tags/index","islogin":"N"}}';
}
}
relatedTag.push(value);
});
return relatedTag;
};
/**
* [处理相关文章数据]
* @param {[array]} getOtherArticle [相关文章原数据]
* @param {[Boolean]} isApp [是否app]
*/
const _relatedInfo = (getOtherArticle, isApp) => {
let relatedInfo = [];
let articleUrl;
getOtherArticle.forEach(value => {
articleUrl = helpers.urlFormat('/info/index', {
id: value.id
}, 'guang');
if (isApp) {
value.url = articleUrl + '&openby:yohobuy={"action":"go.h5","params":{"id":"' + value.id + '","shareparam":{"id":"' + value.id + '"},"islogin":"N","type":1,"url":"http://guang.m.yohobuy.com/info/index","param":{"id":"' + value.id + '"}}}';
} else {
value.url = articleUrl;
}
value.thumb = helpers.image(value.thumb, 279, 175);
relatedInfo.push(value);
});
return relatedInfo;
};
const detailIndex = (req, res, next) => {
let id = req.query.id || req.params[0] || req.params.id,
gender = req.query.gender ||
req.query.channel && typeLib.channels[req.query.channel] ||
req.cookies._Channel && channels[req.cookies._Channel] ||
1,
isApp = req.query.app_version || req.query.appVersion || false, // 标识是不是APP访问的
isWeixin = req.yoho.isWechat,
channel = req.query.channel || req.cookies._Channel,
isqq = req.yoho.isqq,
isWeibo = req.yoho.isWeibo,
isMip = true,
isShare;
res.locals.appPath = `yohobuy://yohobuy.com/goapp?openby:yohobuy={"action":"go.h5","params":{"id":"${id}","share":"/guang/api/v1/share/guang?id=${id}","shareparam":{"id":"${id}"},"islogin":"N","type":1,"url":"http://guang.m.yohobuy.com/info/index","param":{"id":"${id}"}}}`;
// 判断参数是否有效, 无效会跳转到错误页面
if (!stringProcess.isNumeric(id)) {
res.json({
code: 400,
message: '非法请求',
data: ''
});
return;
}
isShare = isWeixin || isqq || isWeibo ? true : false;
co(function* () {
// let mipData = mipUtils.process(testStr, 0);
let detail = yield req.ctx(DetailModel).packageData(id, isApp, isWeixin, channel, isShare);
let data = {
guangDetail: true,
guang: {}
};
data.guang.isWeixin = isWeixin;
data.guang.channel = channel;
data.guang.isShare = isShare;
if (detail.code === 400) {
return next();
}
if (!detail.getArticle) {
// TODO 跳转到逛首页
return;
}
if (isShare && detail && detail.sideNav) {
data.sideNav = detail.sideNav;
}
// 作者信息数据
if (detail && detail.getAuthor && (typeof detail.getAuthor.name !== 'undefined')) {
data.guang.author = {
avatar: detail.getAuthor.avatar.replace('http://', '//'),
name: detail.getAuthor.name,
intro: detail.getAuthor.author_desc
};
// guang双头部的问题 20160601
// 正确的URL
let url = `${detail.getAuthor.url}&openby:yohobuy={"action":"go.h5","params":{"param":{},"share":"","id":${detail.getAuthor.author_id},"type":0,"islogin":"N","url":"${detail.getAuthor.url}"}}`; // eslint-disable-line
data.guang.author.url = helpers.https(url);
}
let guang = data.guang;
guang.detail = {
id: _.get(detail, 'getArticle.id'),
title: detail.getArticle.article_title,
publishTime: detail.getArticle.publishTime,
pageView: detail.getArticle.pageViews,
content: []
};
if (!detail.getArticleContent) {
return next();
}
let processContents = guangProcess.processArticleDetail(detail.getArticleContent,
isApp,
gender,
isWeixin,
isqq,
isWeibo, isMip);
let goodsList = yield req.ctx(DetailModel).productInfoBySkns(processContents.allgoods);
guang.detail.content = guangProcess.pushGoodsInfo(processContents.finalDetail, goodsList, isApp);
// 相关品牌
if (detail.getBrand && detail.getBrand.length) {
guang.relatedBrand = _relatedBrand(detail.getBrand, isApp);
}
// 相关标签
if (detail.getArticle.tags && detail.getArticle.tags.length) {
guang.relatedTag = _relatedTag(detail.getArticle.tags, isApp);
}
// 相关文章
if (detail.getOtherArticle && detail.getOtherArticle.length) {
guang.relatedInfo = _relatedInfo(detail.getOtherArticle, isApp);
}
return res.render('guang/detail', Object.assign({
css: yield css('guang/detail.css'),
gender: gender,
localStyle: processContents.css,
title: detail.getArticle.article_title
}, data));
})().catch(next);
};
module.exports = {
detailIndex
};
... ...
const fs = require('fs');
const path = require('path');
const cssnano = require('cssnano');
const logger = global.yoho.logger;
const css = {};
module.exports = (file) => {
const isNotDev = process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'test';
if (css[file] && isNotDev) {
return Promise.resolve(css[file]);
}
const cssPath = path.join(__dirname, 'css', file);
const cssfile = fs.readFileSync(cssPath).toString();
logger.info(`cssnano process ${cssPath}`);
return cssnano.process(cssfile, {
safe: true,
autoprefixer: {
add: true,
browsers: ['> 1%', 'android >=4', 'ios >=8']
}
}).then(function(result) {
if (result && result.css) {
css[file] = result.css;
return css[file];
}
return '';
}).catch(err => {
logger.error(err);
return '';
});
};
... ...
.guang-detail-c {
max-width: 750px;
width: 100%;
overflow: hidden;
background-color: #f0f0f0;
margin:0 auto;
}
.clearfix:after {
content: '';
display: block;
clear: both;
}
.guang-detail-c .editor-info {
width: 100%;
height: 65px;
border-bottom: 1px solid #e0e0e0;
padding: 0 20px;
background-color: #fff;
}
.editor-info .pic {
border-radius: 50%;
overflow: hidden;
margin-top: 10px;
width: 45px;
height: 45px;
float: left;
}
.editor-info .name {
line-height: 65px;
float: left;
font-size: 14px;
color: #000;
padding-left: 20px;
}
.editor-info .intro {
line-height: 65px;
float: left;
font-size: 14px;
color: #b0b0b0;
padding-left: 20px;
}
.article-info {
padding: 10px 20px;
background-color: #fff;
}
.article-info .name {
line-height: 30px;
font-size: 20px;
color: #000;
font-weight: bold;
}
.article-info .view-c {
color: #b0b0b0;
font-size: 12px;
line-height: 30px;
}
.guang-content {
padding: 0 20px 20px;
background-color: #fff;
float: left;
margin-bottom: 20px;
box-sizing: border-box;
width: 100%;
}
.guang-content p {
padding: 5px 0;
}
.guang-content .pic {
clear: both;
margin: 0 auto;
display: block;
max-width: 100%;
}
.related-goods {
float: left;
width: 100%;
background-color: #fff;
}
.related-goods .good-item {
width: 100%;
border-top: 1px solid #e0e0e0;
float: left;
padding: 20px 0;
}
.related-goods .good-item .pic {
width: 25%;
float: left;
}
.pic-mip {
max-width: 100%;
}
.related-goods .good-item .info {
width: 70%;
float: left;
margin-left: 5%;
}
.related-goods .good-item .name {
color: #000;
padding: 10px 0;
font-size: 14px;
display: -webkit-box;
-webkit-line-clamp: 3;
overflow: hidden;
text-overflow: ellipsis;
-webkit-box-orient: vertical;
line-height: 25px;
}
.related-goods .good-item .price{
color: #d62927;
font-size: 14px;
}
.more-goods {
height: 40px;
line-height: 40px;
clear: both;
border-top: 1px solid #e0e0e0;
border-bottom: 1px solid #e0e0e0;
font-size: 16px;
background-color: #fff;
padding: 0 20px;
display: block;
}
.recommend-goods {
width: 100%;
overflow-x: scroll;
overflow-y: hidden;
margin: 20px 0;
background-color: #fff;
-webkit-overflow-scrolling: touch;
}
.good-scroll {
height: 133px;
margin: 20px 0;
overflow: hidden;
display: inline-flex;
padding-right: 20px;
}
.recommend-goods .good-item {
float: left;
position: relative;
width: 100px;
margin-left: 20px;
}
.recommend-goods .good-item .price{
width: 100px;
height: 20px;
color: #fff;
text-align: center;
line-height: 20px;
position: absolute;
bottom: 0;
left: 0;
background-color: #000;
opacity: 0.7;
}
.related-brand {
background-color: #fff;
}
.brand-c {
width: 100%;
float: left;
background-color: #fff;
}
.related-brand .title {
line-height: 60px;
text-align: center;
color: #000;
font-size: 18px;
background-color: #fff;
}
.brand-item {
width: 20%;
margin: 10px 2.5%;
float: left;
}
.brand-item p {
font-size: 13px;
color: #babac2;
line-height: 20px;
text-align: center;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.brand-tag {
border-top: 1px solid #e0e0e0;
float: left;
background-color: #fff;
width: 100%;
padding-bottom: 20px;
padding-right: 20px;
box-sizing: border-box;
}
.brand-tag .tag{
background-color: #444;
float: left;
color: #fff;
line-height: 30px;
padding: 0 10px;
margin: 20px 0 0 20px;
}
.related-info {
margin: 20px 0;
padding: 20px;
background-color: #fff;
float: left;
padding-bottom: 0;
}
.related-info .info-item {
width: 100%;
float: left;
margin-bottom: 20px;
}
.related-info .info-item .pic {
width: 35%;
float: left;
}
.related-info .info-item .info {
width: 60%;
margin-left: 5%;
float: left;
}
.related-info .info-item .title{
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
word-break: break-all;
overflow: hidden;
line-height: 20px;
}
.related-info .info-item .time {
color: #b0b0b0;
line-height: 22px;
}
.big-pic {
position: relative;
margin-bottom: 3px;
clear: both;
}
.small-pic {
position: relative;
margin-bottom: 3px;
width: 100%;
}
.small-pic .pic {
float: left;
width: 50%;
clear: none;
max-width: 50%;
}
.tag-list-box {
width: 100%;
left: 0;
bottom: 0;
position: absolute;
padding: 10px;
}
.label-box {
clear: both;
}
.lable-info-box {
font-size: 12px;
background-color: rgba(0, 0, 0, 0.6);
color: #fff;
padding: 0 5px;
border-radius: 15px;
float: left;
line-height: 25px;
width: 60%;
height: 25px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-top: 5px;
}
.lable-info-box a {
color: #fff;
overflow: hidden;
text-overflow: ellipsis;
}
.lable-focus {
float: left;
display: flex;
align-items: center;
line-height: 25px;
height: 25px;
margin-right: 15px;
margin-top: 5px;
}
.lable-focus .focus-big {
display: flex;
align-items: center;
width: 17px;
height: 17px;
border-radius: 17px;
border: 4px solid rgba(253, 157, 43, 0.5);
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
}
.lable-focus .focus-small {
width: 17px;
height: 17px;
border-radius: 17px;
background: rgba(253, 157, 43, 1);
-webkit-transform: scale(0.5, 0.5);
transform: scale(0.5, 0.5);
margin: 0;
}
... ...
/**
* sub app service
* @author: xuan.chen@yoho.cn<xuan.chen@yoho.cn>
* @date: 2016/11/21
*/
var express = require('express'),
path = require('path');
var app = express();
// set view engin
var doraemon = path.join(__dirname, '../../doraemon/views'); // parent view root
app.on('mount', function(parent) {
delete parent.locals.settings; // 不继承父 App 的设置
Object.assign(app.locals, parent.locals);
});
app.use(global.yoho.hbs({
extname: '.hbs',
defaultLayout: 'mip',
layoutsDir: doraemon,
partialsDir: [path.join(__dirname, 'views/partial')],
views: path.join(__dirname, 'views/action'),
helpers: global.yoho.helpers
}));
app.locals.layout = 'mip';
// router
app.use(require('./router'));
module.exports = app;
... ...
const cheerio = require('cheerio');
module.exports = {
/**
* 分离 CSS
* @param {*} $
* @param {*} prefix
*/
processStyle($, prefix) {
let css = [];
$('*').each(function(index) {
let $this = $(this);
let localStyle = $this.attr('style');
let className = `yoho-inline-style-${prefix}-${index}`;
if (localStyle) {
css.push(`.${className}{${localStyle}}`);
$this.removeAttr('style');
$this.addClass(className);
}
});
return css.join('');
},
/**
* 替换标签
* @param {*} $
*/
processTag($) {
let css = [];
// mip-anim
$('img[src*=".gif"]').each(function() {
let $this = $(this);
let mipAnim = `<mip-anim layout="responsive" width="350" height="263" src="${$this.attr('src')}" alt="${$this.attr('alt') || ''}" class="${$this.attr('class') || ''}"></mip-anim>`; // eslint-disable-line
$this.replaceWith(mipAnim);
});
// mip-img
$('img').each(function() {
let $this = $(this);
let mipImg = `<mip-img layout="responsive" width="350" height="263" src="${$this.attr('src')}" alt="${$this.attr('alt') || ''}" class="${$this.attr('class') || ''}"></mip-img>`; // eslint-disable-line
$this.replaceWith(mipImg);
});
// mip-video
$('video').each(function() {
let $this = $(this);
let mipVideo = `<mip-video layout="responsive" width="350" height="263" poster="${$this.attr('poster') || ''}" src="${$this.attr('src')}" alt="${$this.attr('alt') || ''}" class="${$this.attr('class') || ''}"></mip-video>`; // eslint-disable-line
$this.replaceWith(mipVideo);
});
// mip-audio
$('audio').each(function() {
let $this = $(this);
let mipAudio = `<mip-audio src="${$this.attr('src')}"></mip-audio>`; // eslint-disable-line
$this.replaceWith(mipAudio);
});
// mip-iframe
$('iframe').each(function() {
let $this = $(this);
let mipIframe = `<mip-iframe layout="responsive" width="350" height="263" src="${$this.attr('src')}" class="${$this.attr('class') || ''}"></mip-iframe>`; // eslint-disable-line
$this.replaceWith(mipIframe);
});
// mip-link
$('a').each(function() {
let $this = $(this);
let mipLink = `<mip-link href="${$this.attr('href')}" class="${$this.attr('class') || ''}" title="${$this.attr('title') || ''}">${$this.html()}</mip-link>`; // eslint-disable-line
$this.replaceWith(mipLink);
});
// style
$('style').each(function() {
let $this = $(this);
css.push($this.html());
$this.remove();
});
return {
mipHtml: $.html(),
css: css.join('')
};
},
/**
* 处理 HTML 为 MIP 所需要的格式
* @param {*} html HTML
* @param {*} prefix CSS 前缀
*/
process(html = '', prefix = 0) {
let $ = cheerio.load(html, {
decodeEntities: false
});
let inlineStyle = this.processStyle($, prefix); // 必须先处理内联样式
let tagHtml = this.processTag($);
return {
mipHtml: tagHtml.mipHtml,
css: tagHtml.css + inlineStyle
};
}
};
... ...
/**
* 逛详情models
* @author: chenfeng<feng.chen@yoho.cn>
* @date: 2016/09/07
*/
'use strict';
const serviceAPI = global.yoho.ServiceAPI;
const api = global.yoho.API;
const _ = require('lodash');
const helpers = global.yoho.helpers;
const URI_PACKAGE_ARTICLE = 'guang/service/v2/article/';
const URI_PACKAGE_AUTHOR = 'guang/service/v1/author/';
class DetailModel extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
}
/**
* 获取二级菜单顶部颜色
* @param {[string]} choosed
* @return {[string]}
*/
_getSidebarColor(choosed) {
let color = false;
if (choosed === 'girls') {
color = '#FF88AE';
} else if (choosed === 'kids') {
color = '#7ad9f9';
} else if (choosed === 'lifestyle') {
color = '#4f4138';
}
return color;
}
/**
* 微信侧边栏导航数据
* @param {*} list
* @param {*} choosed
*/
_processSideBar(list, choosed) {
const formatData = [];
let offset = 0; // 分割数组用到的游标
list = list || [];
_.forEach(list, (item, i) => {
if (item.sub) {
item.sub.unshift({
sort_name: item.sort_name,
sort_name_en: item.sort_name_en,
back: true,
isSelect: false,
bgColor: this._getSidebarColor(choosed)
});
}
// 如果有分隔符,分割数组
if (item.separative_sign === 'Y') {
formatData.push(list.slice(offset, i));
offset = i;
}
});
// 数组被分割剩余的部分
formatData.push(list.slice(offset));
return formatData;
}
_getLeftNav(choosed) {
choosed = choosed || 'all';
return serviceAPI.get('operations/api/v6/category/getCategory', {}, {
cache: true
}).then(result => {
if (result && result.code === 200) {
return this._processSideBar(result.data, choosed);
}
});
}
_getShareData(id) {
return serviceAPI.get('guang/api/v6/share/guang', {
id: id
}).then(result => {
if (result && result.code === 200) {
return result.data;
}
});
}
/**
* 获取文章接口调用
* @param {*} articleId
*/
_getArticle(articleId) {
return serviceAPI.get(`${URI_PACKAGE_ARTICLE}getArticle`, {
article_id: articleId
}, {
cache: true
});
}
/**
* 获取作者接口调用
* @param {*} authorId
*/
_getAuthor(authorId) {
return serviceAPI.get(`${URI_PACKAGE_AUTHOR}getAuthor`, {
author_id: authorId
}, {
cache: true
});
}
/**
* 获取文章详情接口调用
* @param {*} articleId
*/
_getArticleContent(articleId) {
return serviceAPI.get(`${URI_PACKAGE_ARTICLE}getArticleContent`, {
article_id: articleId
}, {
cache: true
});
}
/**
* 获取文章相关品牌接口调用
* @param {*} articleId
*/
_getBrand(articleId) {
return serviceAPI.get(`${URI_PACKAGE_ARTICLE}getBrand`, {
article_id: articleId
}, {
cache: true
});
}
/**
* 获取资讯相关的其它资讯接口调用
* @param {*} articleId
* @param {*} tag
*/
_getOtherArticle(articleId, tag) {
return serviceAPI.get(`${URI_PACKAGE_ARTICLE}getOtherArticle`, {
article_id: articleId,
tags: tag,
offset: 0,
limit: 3
}, {
cache: true
});
}
/**
* APP 获取微信模块
*/
_getSingleTemplateWechat() {
return api.get('', {
method: 'app.resources.getSingleTemplate',
module: 'wechat',
key: 'guang_detail_wechat'
});
}
/**
* [逛资讯详情页数据封装]
* @param {[int]} id [内容ID]
* @param {Boolean} isApp [标识是否是APP访问]
* @return {[array]}
*/
packageData(id, isApp, isWeixin, channel, isShare) {
let result = {
getAuthor: {},
getArticle: {},
getArticleContent: {},
getBrand: {},
getOtherArticle: {}
};
// 获取资讯
return this._getArticle(id).then(data => {
// 调用接口失败
if (!data || data.code !== 200) {
result.code = 400;
return result;
}
let article = result.getArticle = data && data.data || {};
let promises = [
this._getAuthor(article.author_id),
this._getArticleContent(id),
this._getBrand(id)
];
// 获取资讯相关的其它资讯
if (typeof article.tag !== 'undefined') {
promises.push(this._getOtherArticle(id, article.tag));
}
// APP 获取微信模块
if (isApp) {
promises.push(this._getSingleTemplateWechat());
}
if (isShare) {
let navGender = _.cloneDeep(channel);
promises.push(
this._getLeftNav(navGender),
this._getShareData(id)
);
}
return Promise.all(promises).then(datas => {
let getArticleContent = [];
if (!datas) {
return result;
}
if (datas[1]) {
result.getArticleContent = getArticleContent = datas[1].data;
}
if (isApp && datas[4] && datas[4].data) {
let preCount = 0;
let i;
for (i = 0; i < getArticleContent.length; i++) {
if (getArticleContent[i].singleImage ||
getArticleContent[i].text || getArticleContent[i].smallPic) {
preCount++;
}
}
_.forEach(datas[4].data, item => {
item.src = helpers.image(item.src, 280, 210, 1);
});
getArticleContent.splice(preCount, 0, {
weixinPublic: datas[4].data
});
}
if (isShare && datas[5]) {
if (datas[5].wechatShareImgUrl) {
datas[5].wechatShareImgUrl =
datas[5].wechatShareImgUrl.substring(datas[5].wechatShareImgUrl.indexOf('//'));
if (datas[5].wechatShareImgUrl.indexOf('?') === -1) {
datas[5].wechatShareImgUrl = datas[5].wechatShareImgUrl +
'?imageView2/2/interlace/1/q/75';
}
} else if (datas[5].qqShareImgUrl) {
datas[5].qqShareImgUrl =
datas[5].qqShareImgUrl.substring(datas[5].qqShareImgUrl.indexOf('//'));
if (datas[5].qqShareImgUrl.indexOf('?') === -1) {
datas[5].qqShareImgUrl = datas[5].wechatShareImgUrl + '?imageView2/2/interlace/1/q/75';
}
} else if (datas[5].showShareImgUrl) {
datas[5].showShareImgUrl =
datas[5].showShareImgUrl.substring(datas[5].showShareImgUrl.indexOf('//'));
if (datas[5].showShareImgUrl.indexOf('?') === -1) {
datas[5].showShareImgUrl = datas[5].showShareImgUrl + '?imageView2/2/interlace/1/q/75';
}
}
let preCount = 0;
let i;
for (i = 0; i < getArticleContent.length; i++) {
if (getArticleContent[i].singleImage ||
getArticleContent[i].text || getArticleContent[i].smallPic) {
preCount = i + 1;
}
}
getArticleContent.splice(preCount, 0, {
shareCode: datas[5]
});
}
if (datas[0]) {
result.getAuthor = datas[0].data;
}
if (datas[2]) {
result.getBrand = datas[2].data;
}
if (isShare && datas[4]) {
result.sideNav = datas[4];
}
if (datas.length === 5 && isApp || datas.length === 4 && !isApp || datas.length === 6 && isShare) {
if (datas[3]) {
result.getOtherArticle = datas[3].data;
}
}
return result;
});
});
}
/**
* [获取详情信息]
* @param {[int]} id [资讯id]
* @return {[object]}
*/
intro(id) {
let param = {
article_id: id,
client_type: 'h5'
};
return serviceAPI.get(`${URI_PACKAGE_ARTICLE}getArticleContent`, param, {
cache: true
});
}
/**
* [根据商品SKN获取商品的简要信息]
* @param {[array]} sknString [skns]
* @return {[type]}
*/
productInfoBySkns(sknString) {
// 调用搜索接口
let param = {
method: 'h5.product.batch',
productSkn: sknString,
order: 's_t_desc'
};
return api.get('', param, {
cache: true
}).then(result => {
return _.get(result, 'data.product_list', []);
});
}
}
module.exports = DetailModel;
... ...
/**
* router of sub app service
* @author: xuan.chen@yoho.cn<xuan.chen@yoho.cn>
* @date: 2016/11/21
*/
'use strict';
const router = require('express').Router(); //eslint-disable-line
const cRoot = './controllers';
const rewrite = require('../../doraemon/middleware/rewrite');
const mip = require('../../doraemon/middleware/mip');
const guang = require(`${cRoot}/guang`);
router.use(mip);
router.get(/^\/guang\/info\/(.*?)\.html/, rewrite.resolve, guang.detailIndex);
module.exports = router;
... ...
<div class="guang-detail-c">
{{# guang}}
{{# author}}
<div class="editor-info" data-id={{id}}>
<mip-link href="{{url}}">
<mip-img class="pic" width="45" height="45" src={{image2 avatar mode=2 q=60}}>
</mip-img>
<div class="name">{{name}}</div>
<div class="intro">{{intro}}</div>
</mip-link>
</div>
{{/ author}}
{{# detail}}
<div class="article-info">
<p class="name">{{title}}</p>
<div class="view-c">
<span>日期:{{publishTime}}</span>
</div>
</div>
<div class="guang-content clearfix">
{{# content}}
{{#if text}}
{{{text}}}
{{/if}}
{{#if bigImage}}
<div class="big-pic">
{{#if isGif}}
<mip-anim class="pic" width="{{width}}" height="{{height}}" src="{{image2 bigImage q=60}}"></mip-anim>
{{else}}
<mip-img class="pic" width="{{width}}" height="{{height}}" src="{{image2 bigImage q=60}}"></mip-img>
{{/if}}
{{#if tagList}}
<div class="tag-list-box">
{{#each tagList}}
{{#unless isApp}}
<div class="label-box" data-skn="{{product_skn}}">
<div class="lable-focus">
<div class="focus-big">
<div class="focus-small"></div>
</div>
</div>
<div class="lable-info-box{{#if isApp}} lable-infobox-borderadius{{/if}}"><mip-link href="{{href}}">{{tagName}}</mip-link></div>
<div class="lable-btn add-to-cart" data-skn="{{product_skn}}">
</div>
</div>
{{/unless}}
{{/each}}
</div>
{{/if}}
</div>
{{/if}}
{{#if smallImage}}
<div class="small-pic">
{{# smallImage}}
{{#if isGif}}
<mip-anim class="pic" width="160" height="160" src="{{image2 src q=60}}"></mip-anim>
{{else}}
<mip-img class="pic" width="160" height="160" src="{{image2 src q=60}}"></mip-img>
{{/if}}
{{/ smallImage}}
</div>
{{/if}}
{{#if relatedReco}}
<div class="related-goods clearfix">
{{#each relatedReco.goods}}
{{#if url}}
<div class="good-item">
<mip-link href="{{url}}">
{{#if default_images}}
<div class="pic">
<mip-img class="pic-mip" width="76" height="102" src="{{image2 default_images w=152 h=204}}">
</mip-img>
</div>
{{/if}}
<div class="info">
<p class="name">{{product_name}}</p>
{{#if sales_price}}
<p class="price">&yen;{{sales_price}}</p>
{{/if}}
</div>
</mip-link>
</div>
{{/if}}
{{/each}}
</div>
{{/if}}
{{/ content}}
</div>
{{/ detail}}
{{#detail.content}}
{{#if moreLink}}
<mip-link class="more-goods" href="{{moreLink}}">更多商品</mip-link>
{{/if}}
{{#if recommendProducts}}
<div class="recommend-goods">
<div class="good-scroll">
{{#each recommendProducts}}
<div class="good-item">
<mip-link href="{{href}}">
<mip-img class="pic" width="100" height="134" src="{{image2 pic_url w=152 h=204}}">
</mip-img>
</mip-link>
<p class="price">&yen;{{price}}</p>
</div>
{{/each}}
</div>
</div>
{{/if}}
{{/detail.content}}
{{#if relatedBrand}}
<div class="related-brand clearfix">
<div class="title">相关品牌</div>
<div class="brand-c">
{{# relatedBrand}}
<div class="brand-item">
<mip-link href="{{url}}">
<div class="pic">
<mip-img class="pic-mip" width="75" height="75" src="{{thumb}}">
</mip-img>
</div>
<p>{{name}}</p>
</mip-link>
</div>
{{/ relatedBrand}}
</div>
</div>
{{/if}}
{{#if relatedInfo}}
<div class="related-info">
{{# relatedInfo}}
<div class="info-item">
<mip-link href="{{url}}">
<div class="pic">
<mip-img class="pic-mip" width="117" height="73" src="{{thumb}}">
</mip-img>
</div>
<div class="info">
<p class="title">{{title}}</p>
<p class="time">{{publishTime}}</p>
</div>
</mip-link>
</div>
{{/ relatedInfo}}
</div>
{{/if}}
{{#if relatedTag}}
<div class="brand-tag">
{{# relatedTag}}
<mip-link href="//guang.m.yohobuy.com/tags/index?query={{name}}" class="tag">{{name}}</mip-link>
{{/ relatedTag}}
</div>
{{/if}}
{{/ guang}}
</div>
... ...
... ... @@ -14,6 +14,7 @@ const crypto = global.yoho.crypto;
const helpers = global.yoho.helpers;
const productProcess = require(`${utils}/product-process`);
const searchModel = require(`${mRoot}/search`);
const searchProcess = require(`${utils}/search-process`);
/**
* 从 useragent 获取 uid
... ... @@ -236,7 +237,7 @@ const category = (req, res, next) => {
}
searchModel.getSearchData(initialData).then((firstPageGoods) => {
res.render('search/goods-list', {
res.render('search/goods-list', Object.assign({
_noLazy: true, // 首屏不使用lazyload
module: 'product',
page: 'search-list',
... ... @@ -252,7 +253,7 @@ const category = (req, res, next) => {
localCss: true,
appPath: appPath,
introText: req.query.intro_text
});
}, searchProcess.getListSeoData(req.query.gender, req.query.title || req.query.sort_name)));
}).catch(next);
};
... ...
... ... @@ -51,7 +51,13 @@ const newDetail = {
pageHeader: headerData,
result: result,
page: 'new-detail',
title: result.goodsName,
title: result.goodsName + result.sortName + '正品 | YOHO!BUY 有货',
keywords: result.brandName + result.sortName + ',' + result.brandName + '官网专卖店,' +
result.brandName + '官方授权店,' + result.brandName + '正品,' + result.brandName + '打折,' +
result.brandName + '折扣店,' +
result.brandName + '真品,' + result.brandName + '代购',
description: `YOHO!BUY 有货-${result.brandName}官方授权店,${result.goodsName}图片、报价、介绍。` +
`YOHO!BUY 有货${result.brandName}官网专卖店提供${result.brandName}正品、${result.brandName}真品、 ${result.brandName}打折、${result.brandName}代购等。`, // eslint-disable-line
pageFooter: true,
localCss: true,
appPath: appPath
... ...
... ... @@ -431,6 +431,10 @@ const shop = {
let decorators = redShopPrcs.pushGoodsInfo(decoratorsAll.decorators, goodsList);
res.render('newshop/shop-reds', {
title: shopInfo.shop_name + '|' + shopInfo.shop_name + '潮流服装服饰-Yoho!Buy有货',
keywords: shopInfo.shop_name + ',' + shopInfo.shop_name + '服装服饰,' + shopInfo.shop_name + '潮流服装服饰',
description: shopInfo.shop_name + '|Yoho!Buy有货' + shopInfo.shop_name +
'潮流服饰官方授权店!100%品牌正品保证,支持货到付款。',
pageHeader: _.assign({
shopPage: {
text: '分类',
... ...
... ... @@ -182,7 +182,7 @@ let discountDetail = (req, res, next) => {
params.renderData.pageHeader.navTitle = result.title;
// 唤起 APP 的路径
res.locals.appPath = `yohobuy://yohobuy.com/goapp?openby:yohobuy={"action":"go.discountmarketpro","params":{"id":"${id}","cover_url":"${result.activity.cover_url.split('?')[0]}","title":"${result.title}"}}`;
res.locals.appPath = result.activity && result.activity.cover_url ? `yohobuy://yohobuy.com/goapp?openby:yohobuy={"action":"go.discountmarketpro","params":{"id":"${id}","cover_url":"${result.activity.cover_url.split('?')[0]}","title":"${result.title}"}}` : '';
res.render('sale/discount-detail', Object.assign(params.renderData, result, {
localCss: true
... ...
... ... @@ -174,7 +174,7 @@ const index = (req, res, next) => {
}
})((result) => {
res.render('search/index', {
res.render('search/index', Object.assign({
module: 'product',
page: 'search-index',
pageHeader: headerModel.setNav({
... ... @@ -190,7 +190,7 @@ const index = (req, res, next) => {
wantTerms: result.guessTerms
}
});
}, searchProcess.getListSeoData()));
});
};
... ...
... ... @@ -132,6 +132,8 @@ const tool = {
// 底部简介URL链接
dest.introUrl = '/product/detail/intro/' + origin.product_skn;
dest.brandName = _.get(origin, 'brand_info.brand_name', '');
dest.sortName = _.get(origin, 'middle_sort_name', '');
return dest;
},
... ...
... ... @@ -30,4 +30,7 @@ module.exports = app => {
// 用户服务: 在线客服
app.use('/service', require('./apps/service'));
// MIP
app.use('/mip', require('./apps/mip'));
};
... ...
'use strict';
module.exports = (req, res, next) => {
Object.assign(res.locals, {
canonical: 'https://m.yohobuy.com' + req.path,
miphtml: 'https://m.yohobuy.com/mip' + req.originalUrl
});
next();
};
... ...
... ... @@ -25,56 +25,66 @@ const seoMap = {
keywords: '创意生活,创意生活馆,潮流家居,潮流创意家居,家居生活用品,Yoho!Buy有货',
description: 'Yoho!BUY有货官网创意生活频道提供了潮流创意家居,家居生活用品等正品网购,给您的生活带来更多创意。'
},
'/product/sale?channel=boys': {
'/product/boys-sale/': {
title: '折扣男装专区|男装SALE折扣,男款鞋包配饰特卖|Yoho!Buy有货 100%正品保证',
keywords: 'SALE,男装SALE,男装折扣,男款鞋包配饰特卖',
description: 'Yoho!Buy有货SALE频道提供男装折扣,精致品牌男装sale,限时特惠。Yoho!Buy有货男装折扣,100%正品保证!'
},
'/product/sale?gender=2,3': {
'/product/girls-sale/': {
title: '折扣女装专区|女装SALE折扣,女款鞋包配饰特卖|Yoho!Buy有货',
keywords: 'SALE,女装SALE,女装折扣,女款鞋包配饰特卖',
description: 'Yoho!Buy有货SALE频道提供女装折扣,精致品牌女装sale,限时特惠。Yoho!Buy有货女装折扣,100%正品保证!'
},
'/product/new?gender=1,3': {
'/product/kids-sale/': {
title: 'SALE|童装SALE,童装折扣,潮童鞋包配饰特卖|YOHO!BUY有货',
keywords: 'SALE,童装SALE,童装折扣,潮童鞋包配饰特卖',
description: 'YOHO!BUY有货SALE频道提供童装折扣,精致品牌童装sale,童装,针织衫,外套 卫衣,夹克,棉衣,裤子,品牌童鞋,潮童鞋包配饰等限时特惠。YOHO!BUY有货潮童折扣,100%正品保证!'
},
'/product/lifestyle-sale/': {
title: 'SALE|家居生活用品SALE,生活用品折扣,数码家居特卖YOHO!BUY有货',
keywords: 'SALE,家居生活用品SALE,生活用品折扣,数码家居特卖',
description: 'YOHO!BUY有货SALE频道提供生活用品折扣,数码家居特卖,数码3c,居家,玩具娱乐,文具,美妆等限时特惠。YOHO!BUY有货家居生活用品SALE,,100%正品保证! '
},
'/product/boys-new/': {
title: '男生潮装新品|男装新品发布,饰品推荐|Yoho!Buy有货 ',
keywords: '男生潮装新品,新品发布,新品男装,新款男装推荐,新款男鞋推荐,新款男包推荐,新款男饰品推荐,Yoho!Buy有货',
description: 'Yoho!Buy有货男装新品到着为您提供新品男装,男装新品直达就选Yoho!Buy有货,100%正品保证!'
},
'/product/new?gender=2,3': {
'/product/girls-new/': {
title: '女生潮装新品|女装新品发布,饰品推荐|Yoho!Buy有货 ',
keywords: '女生潮流新品,女款新品发布,新品女装,新款女装推荐,新款女鞋推荐,新款女包推荐,新款饰品推荐,Yoho!Buy有货',
description: 'Yoho!Buy有货女装新品到着为您提供新品女装,女装样品,女装新款推荐;汇集国内外最新款女装,鞋,女包,饰品,100%正品保证!'
},
'/product/new?msort=365&channel=4': {
'/product/kids-new/': {
title: '新品到着|潮童新品发布,新款童装童鞋,包包配饰推荐|Yoho!Buy有货',
keywords: '潮童新品发布,新品童装,新款童装推荐,新款童鞋,新款儿童鞋包,儿童配饰新品,Yoho!Buy有货',
description: 'Yoho!Buy有货潮童新品到着为您提供新品童装,童装样品,童装新款推荐;汇集国内外最新款童装,童鞋,儿童鞋包配饰。'
},
'/product/new?msort=10&channel=4': {
'/product/lifestyle-new/': {
title: '新品到着|数码3c,居家,玩具娱乐,文具,美妆|Yoho!Buy有货',
keywords: '数码3c,居家,玩具娱乐,文具,美妆,Yoho!Buy有货',
description: 'Yoho!Buy有货创意生活新品到着为您提供潮流创意生活,汇集国内外最新款数码3c,居家,玩具娱乐,文具,美妆。'
},
'/brands?channel=1': {
'/boys-brands/': {
title: '潮流男装品牌|男装品牌排行榜,男装品牌大全|Yoho!Buy有货',
keywords: '潮流男装品牌,男装品牌,男装品牌排行榜,男装品牌大全,Yoho!Buy有货',
description: 'Yoho!Buy有货男装品牌一览汇集国内国际各大男装品牌大全,为广大爱好时尚的男士青年提供品牌男装、休闲男装、商务男装.Yoho!Buy有货,100%正品保证'
},
'/brands?channel=2': {
'/girls-brands/': {
title: '潮流女装品牌|女装品牌排行榜,女装品牌大全|Yoho!Buy有货',
keywords: '潮流女装品牌,女装品牌,女装品牌排行榜,女装品牌大全,Yoho!Buy有货',
description: 'Yoho!Buy有货女装品牌一览汇集各大女装品牌,提供品牌女装、休闲女装、商务女装.Yoho!Buy有货品牌女装100%正品保证。'
},
'/brands?channel=3': {
'/kids-brands/': {
title: '品牌一览|童装童鞋品牌,儿童鞋包配饰排行榜大全|Yoho!Buy有货',
keywords: '童装品牌,童装童鞋排行榜,儿童鞋包配饰排行榜,潮童品牌大全,品牌一览,Yoho!Buy有货',
description: 'Yoho!Buy有货童装品牌一览汇集国内国际各大童装品牌大全,提供品牌童装、童鞋,儿童鞋包配饰,100%正品保证'
},
'/brands?channel=4': {
'/lifestyle-brands/': {
title: '品牌一览|数码3c,居家,玩具娱乐,文具,美妆品牌|Yoho!Buy有货',
keywords: '数码3c品牌,居家品牌,玩具娱乐品牌,文具品牌,美妆品牌',
description: 'Yoho!Buy有货女装品牌一览汇集国内国际各大数码3c品牌,居家品牌,玩具娱乐品牌,文具品牌,美妆品牌.'
},
}
/* eslint-enable */
};
... ...
... ... @@ -12,8 +12,11 @@
<meta content="email=no" name="format-detection" />
<meta name="referrer" content="always">
{{# cononical}}
<link rel="cononical" href="{{currentHref}}"/>
<link rel="cononical" href="{{currentHref}}">
{{/ cononical}}
{{#if miphtml}}
<link rel="miphtml" href="{{miphtml}}">
{{/if}}
{{#dnsPrefetch.hosts}}
<link rel="dns-prefetch" href="{{this}}">
{{/dnsPrefetch.hosts}}
... ... @@ -23,7 +26,7 @@
var isWechat = /micromessenger/i.test(navigator.userAgent || '');
if (isWechat) {
document.title =document.title.replace(' | Yoho!Buy有货 | 潮流购物逛不停', '');
(function () { if (typeof (WeixinJSBridge) == "undefined") { document.addEventListener("WeixinJSBridgeReady", function (a) { setTimeout(function () { WeixinJSBridge.invoke("setFontSizeCallback", { fontSize: 0 }, function (b) { }) }, 0) }) } else { setTimeout(function () { WeixinJSBridge.invoke("setFontSizeCallback", { fontSize: 0 }, function (a) { }) }, 0) } })();
(function(){function setWechatSize(){if(typeof WeixinJSBridge!=="undefined"&&WeixinJSBridge.invoke){WeixinJSBridge.invoke("setFontSizeCallback",{fontSize:0},function(){})}}if(typeof WeixinJSBridge!=="undefined"){setTimeout(setWechatSize,0)}else{document.addEventListener("WeixinJSBridgeReady",function(){setTimeout(setWechatSize,0)})};}());
}
</script>
... ...
<!DOCTYPE html>
<html mip>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
<title>{{title}} | Yoho!Buy有货 | 潮流购物逛不停</title>
<link rel="stylesheet" type="text/css" href="https://mipcache.bdstatic.com/static/v1/mip.css">
<link rel="canonical" href="{{canonical}}">
<style mip-custom>
.main-wrap{width: 100%;max-width: 750px;margin: 0 auto;}
{{css}}
{{localStyle}}
</style>
</head>
<body>
<div class="main-wrap">{{{body}}}</div>
<mip-stats-baidu token="d22478778b220ee60bce74bd15d390ae" setconfig="%5B'_trackEvent'%2C%20'mip'%2C%20'{{canonical}}'%5D"></mip-stats-baidu>
<script src="https://mipcache.bdstatic.com/static/v1/mip.js"></script>
<script src="https://mipcache.bdstatic.com/static/v1/mip-stats-baidu/mip-stats-baidu.js"></script>
<script src="https://mipcache.bdstatic.com/static/v1/mip-anim/mip-anim.js"></script>
<script src="https://mipcache.bdstatic.com/static/v1/mip-link/mip-link.js"></script>
<script src="https://mipcache.bdstatic.com/static/v1/mip-audio/mip-audio.js"></script>
</body>
</html>
... ...
... ... @@ -12,7 +12,7 @@
a.async = 1;
a.src = j;
m.parentNode.insertBefore(a, m);
}(window, document, 'script', (document.location.protocol === 'https:' ? 'https:' : 'http:') + '//cdn.yoho.cn/yas-jssdk/2.4.0/yas.js', '_yas'));
}(window, document, 'script', (document.location.protocol === 'https:' ? 'https:' : 'http:') + '//cdn.yoho.cn/yas-jssdk/2.4.1/yas.js', '_yas'));
var _hmt = _hmt || [];
... ... @@ -56,7 +56,7 @@
uid = uid === 0 ? '' : uid;
window._ozuid = uid; // 暴露ozuid
if (window._yas) {
window._yas(1 * new Date(), '2.4.0', 'yohobuy_m', uid, '', '');
window._yas(1 * new Date(), '2.4.1', 'yohobuy_m', uid, '', '');
}
setTimeout(function() {
... ... @@ -75,7 +75,7 @@
}, 1000);
}());
/* tar add 170426 品众代码去除 */
{{!--/* tar add 170426 品众代码去除 */--}}
{{!--window._fxcmd = window._fxcmd || [];
_fxcmd.sid = 'bb3b16fa1106a6ab8619da0095755f32';
_fxcmd.trackAll = false;
... ...
{
"name": "m-yohobuy-node",
"version": "5.7.1",
"version": "5.7.3",
"private": true,
"description": "A New Yohobuy Project With Express",
"repository": {
... ... @@ -26,6 +26,7 @@
"body-parser": "^1.16.1",
"captchapng": "0.0.1",
"cheerio": "^0.22.0",
"cssnano": "^3.10.0",
"client-sessions": "^0.8.0",
"compression": "^1.6.2",
"connect-memcached": "^0.2.0",
... ... @@ -52,7 +53,7 @@
"xml2js": "^0.4.17",
"yoho-express-session": "^2.0.0",
"yoho-md5": "^2.0.0",
"yoho-node-lib": "=0.2.25",
"yoho-node-lib": "=0.2.27",
"yoho-zookeeper": "^1.0.8"
},
"devDependencies": {
... ... @@ -62,7 +63,6 @@
"babel-polyfill": "^6.23.0",
"babel-preset-env": "^1.4.0",
"css-loader": "^0.28.1",
"cssnano": "^3.10.0",
"eslint": "^3.19.0",
"eslint-config-yoho": "^1.0.1",
"eslint-loader": "^1.7.1",
... ... @@ -103,7 +103,7 @@
"yoho-fastclick": "^1.0.6",
"yoho-hammer": "^2.0.7",
"yoho-iscroll": "^5.2.0",
"yoho-jquery": "^2.2.4",
"yoho-jquery": "^1.12.4",
"yoho-jquery-lazyload": "^1.9.12",
"yoho-jquery-qrcode": "^0.14.0",
"yoho-mlellipsis": "0.0.3",
... ...
... ... @@ -306,7 +306,7 @@ plusstar = {
});
}, 300);
},
goodsList: function() {
goodsList: function(reload) {
let that = this,
skn = [];
... ... @@ -319,6 +319,10 @@ plusstar = {
return false;
}
if (!reload) {
$('.goods').append('<div class="divide">正在加载...</div>');
}
loading.showLoadingMask();
skn = that.common.productSkns.slice((that.common.page - 1) *
that.common.pagesize, that.common.page * that.common.pagesize);
... ... @@ -356,6 +360,7 @@ plusstar = {
PAGE_NUM: that.common.page - 1
});
$('.divide').remove();
$('.plusstar-resources .goods').append(data);
$('.plusstar-resources .goods').find('img.lazy:not([src])').lazyload();
... ... @@ -399,6 +404,8 @@ $(function() {
plusstar.init();
plusstar.goodsList(true);
// 滚动翻页
$(window).scroll(function() {
scrollFn();
... ...
... ... @@ -15,13 +15,13 @@ let fCbFn, hCbFn; // 筛选和关闭的回调
// 隐藏筛选界面
function hideFilter() {
setTimeout(function() {
$filter.addClass('hide');
$filter && $filter.addClass('hide');
}, 301);
}
// 显示筛选界面
function showFilter() {
$filter.removeClass('hide');
$filter && $filter.removeClass('hide');
}
// 一级菜单点击时背景高亮
... ...
... ... @@ -356,6 +356,10 @@ function filterInit() {
url: '/product/sale/filter',
data: defaultOpt,
success: function(data) {
if (data === '') {
return false;
}
$goodsContainer.append(data);
// 初始化filter&注册filter回调
... ...
... ... @@ -198,6 +198,15 @@
.goods {
background-color: #fff;
padding: 0 14px;
.divide {
float: left;
height: 50px;
width: 100%;
padding: 10px 0;
color: #ccc;
text-align: center;
}
}
}
... ...
... ... @@ -6,6 +6,7 @@
const _ = require('lodash');
const helpers = global.yoho.helpers;
const productPrcs = require('./product-process');
const mipUtils = require('../apps/mip/mip-utils');
/**
* 将商品转化成以 product_skn 为键名的对象
... ... @@ -206,16 +207,27 @@ const getProductIcon = (type) => {
/**
* 逛详情页数据处理
*/
const processArticleDetail = (articleContent, isApp, gender, isWeixin, isqq, isWeibo) => {
const processArticleDetail = (articleContent, isApp, gender, isWeixin, isqq, isWeibo, isMip) => {
let finalDetail = [];
let allgoods = '';
let localStyle = [];
_.forEach(articleContent, (value, index) => {
// 文字
if (_.get(value, 'text.data.text', false)) {
let newText = '';
if (isMip) {
let mipHtml = mipUtils.process(value.text.data.text, index);
newText = mipHtml.mipHtml;
localStyle.push(mipHtml.css);
} else {
newText = value.text.data.text;
}
finalDetail.push({
text: value.text.data.text
text: newText
});
}
... ... @@ -235,7 +247,10 @@ const processArticleDetail = (articleContent, isApp, gender, isWeixin, isqq, isW
finalDetail.push({
bigImage: helpers.image(_.get(value, 'singleImage.data[0].src', ''), 640, 640),
noLazy: index <= 3,
tagList: tagList
tagList: tagList,
isGif: /\.gif/i.test(_.get(value, 'singleImage.data[0].src', '')),
width: 320,
height: _.get(value, 'singleImage.data[0].height', 0) / _.get(value, 'singleImage.data[0].width', 1) * 320 // eslint-disable-line
});
}
... ... @@ -244,12 +259,14 @@ const processArticleDetail = (articleContent, isApp, gender, isWeixin, isqq, isW
finalDetail.push({
smallImage: [
{
src: helpers.image(_.get(value, 'smallPic.data[0].src', ''), 315, 420)
src: helpers.image(_.get(value, 'smallPic.data[0].src', ''), 315, 420),
isGif: /\.gif/i.test(_.get(value, 'smallPic.data[0].src', '')),
},
{
src: helpers.image(_.get(value, 'smallPic.data[1].src', ''), 315, 420)
src: helpers.image(_.get(value, 'smallPic.data[1].src', ''), 315, 420),
isGif: /\.gif/i.test(_.get(value, 'smallPic.data[0].src', '')),
}
],
]
});
}
... ... @@ -296,8 +313,7 @@ const processArticleDetail = (articleContent, isApp, gender, isWeixin, isqq, isW
finalDetail.push({
relatedReco: {
isApp: isApp,
goods: goodsData,
moreNum: goodsData.length - 2 > 0 ? goodsData.length - 2 : 0
goods: goodsData
}
});
}
... ... @@ -350,7 +366,8 @@ const processArticleDetail = (articleContent, isApp, gender, isWeixin, isqq, isW
return {
finalDetail: finalDetail,
allgoods: allgoods
allgoods: allgoods,
css: localStyle.join('')
};
};
... ... @@ -362,9 +379,26 @@ const pushGoodsInfo = (finalDetail, goodsList, isApp) => {
_.forEach(finalDetail, (value, key) => {
if (value.relatedReco) {
_.forEach(value.relatedReco.goods, (item, subKey) => {
finalDetail[key].relatedReco.goods[subKey] = goodsObj[item.id];
let goodsIds = [];
_.forEach(value.relatedReco.goods, relatedGoods => {
goodsIds.push(relatedGoods.id);
});
goodsIds = _.uniq(goodsIds);
finalDetail[key].relatedReco.goods = [];
_.forEach(goodsIds, (item, subKey) => {
if (goodsObj[item]) {
finalDetail[key].relatedReco.goods[subKey] = goodsObj[item];
} else {
delete finalDetail[key].relatedReco.goods[subKey];
}
});
let moreNum = _.get(finalDetail[key], 'relatedReco.goods.length', 0);
finalDetail[key].relatedReco.moreNum = moreNum - 2 > 0 ? moreNum - 2 : 0;
}
if (value.collocation) {
... ...
... ... @@ -143,6 +143,24 @@ module.exports = {
return '';
}
},
/**
* 图片质量调整
*/
imageslim: function(imageUrl) {
if (imageUrl && _.isString(imageUrl)) {
let urls = imageUrl.split('?');
let uri = urls[0];
if (uri.indexOf('http:') === 0) {
uri = uri.replace('http:', '');
}
return uri + '?imageslim';
} else {
return '';
}
},
isEqualOr: function() {
let args = Array.prototype.slice.call(arguments);
let v1 = args[0];
... ...
... ... @@ -4,6 +4,12 @@
* @date: 2016/7/29
*/
const _getGender = {
'1,3': '男生',
'2,3': '女生',
'1,2,3': '',
};
/**
* 根据频道判断出性别
*/
... ... @@ -66,8 +72,31 @@ const getTypeCont = (type, order) => {
}
};
/**
* 品类列表页 SEO 数据
* @param {*} gender
* @param {*} sort_name
*/
const getListSeoData = (gender, sort_name) => {
let seoData = {
title: '潮流服装配饰,创意生活用品_男生|女生|潮童服装,鞋履,配饰品牌正品-YOHO!BUY有货',
keywords: '潮流服装配饰,创意生活用品,男生服装配饰,女生服装配饰,潮童服装配饰',
description: '潮流服装配饰及创意生活正品网购!YOHO!BUY有货提供男生、女生、潮童服装配饰。100%品牌正品保证,支持货到付款。'
};
if (gender && sort_name) {
seoData = {
title: `${sort_name}|新款${sort_name}${_getGender[gender]}|品牌正品|YOHO!BUY有货`,
keywords: `新款${sort_name},${_getGender[gender]}${sort_name},品牌正品`,
description: `正品网购!YOHO!BUY有货提供新款${sort_name}${_getGender[gender]}${sort_name}100%品牌正品保证,支持货到付款。`
};
}
return seoData;
};
module.exports = {
getGenderByChannel,
getChannelType,
getTypeCont
getTypeCont,
getListSeoData
};
... ...