Authored by 陈峰

逛详情页面开发完成

... ... @@ -21,11 +21,11 @@ const channels = {
const _index = (req, res, next) => {
let id = req.query.id,
gender = req.query.gender || req.cookies._Channel && channels[req.cookies._Channel] || 1,
isApp = req.query.app_version || req.query.appVersion || false, //标识是不是APP访问的
isApp = req.query.app_version || req.query.appVersion || false, // 标识是不是APP访问的
parameter = {},
title = '逛',
userAgent = req.get('User-Agent'),
isWeixin = userAgent.includes('MicroMessenger'); //标识是否是微信访问
isWeixin = userAgent.includes('MicroMessenger'); // 标识是否是微信访问
// 判断参数是否有效, 无效会跳转到错误页面
if (!stringProcess.isNumeric(id)) {
... ... @@ -33,13 +33,6 @@ const _index = (req, res, next) => {
return;
}
let data = {
guangDetail: true,// 模板中使用JS的标识
guang: {
id: id
}
}
// WAP上设置头部导航
if (!isApp && !isWeixin) {
parameter = {
... ... @@ -52,25 +45,30 @@ const _index = (req, res, next) => {
// 获取详情内容信息, 异常则跳到错误页面
return infoModel.package(id, isApp).then(detail => {
let data = {};
let data = {
guang: {}
};
if (detail.code !== 400) {
if (!detail.getArticle) {
//TODO 跳转到逛首页
// TODO 跳转到逛首页
return;
}
// 作者信息数据
if (detail.getAuthor.name) {
data.author = {
data.guang.author = {
avatar: detail.getAuthor.avatar.replace('http://', '//'),
name: detail.getAuthor.name,
intro: detail.getAuthor.author_desc
};
// guang双头部的问题 20160601
data.guang.author.url = helpers.https(`${detail.getAuthor.url}&openby:yohobuy={"action":"go.h5","params":{"param":{"id":"${detail.getAuthor.author_id}"},"share":"","id":${detail.getAuthor.author_id},"type":0,"islogin":"N","url":"${helpers.urlFormat('/author/index', {}, 'guang')}"}}`);
}
//guang双头部的问题 20160601
data.author.url = helpers.https(`${detail.getAuthor.url}&openby:yohobuy={"action":"go.h5","params":{"param":{"id":"${detail.getAuthor.author_id}"},"share":"","id":${detail.getAuthor.author_id},"type":0,"islogin":"N","url":"${helpers.urlFormat('/author/index', {}, 'guang')}"}}`)
}
data.detail = {
let guang = data.guang;
guang.detail = {
title: detail.getArticle.article_title,
publishTime: detail.getArticle.publishTime,
pageView: detail.getArticle.pageViews,
... ... @@ -79,41 +77,42 @@ const _index = (req, res, next) => {
let callArticleContent = (i, len, resolve) => {
if (i < len) {
let art = detail.getArticleContent[i];
let build = {},
good = {},
skns = {},
product = {};
let build = {};
// 文字
if (art.text && art.text.data && art.text.data.text) {
build.text = art.text.data.text;
data.detail.content.push(build);
guang.detail.content.push(build);
callArticleContent(++i, len, resolve);
} else if (art.singleImage) { // 单张图
build.bigImage = helpers.image(art.singleImage.data[0].src, 640, 640);
data.detail.content.push(build);
guang.detail.content.push(build);
callArticleContent(++i, len, resolve);
} else if (art.smallPic && art.smallPic.data) {
let imgs = art.smallPic.data;
build.smallImage = [{
src: helpers.image(imgs[0].src, 315, 420)
}, {
src: helpers.image(imgs[1].src, 315, 420)
}
]
data.detail.content.push(build);
];
guang.detail.content.push(build);
callArticleContent(++i, len, resolve);
} else if (art.goods && art.goods.data) { // 相关推荐
let reco = [],
skns = [],
arr = [];
// 遍历取得SKN
art.goods.data.forEach(goods => {
skns.push(goods.id);
arr[goods.id]=goods.src;
arr[goods.id] = goods.src;
});
// callArticleContent(++i, len, resolve);
// return;
// 通过SKN获取商品信息
... ... @@ -121,22 +120,22 @@ const _index = (req, res, next) => {
// console.log(product)
if (product.data.product_list) {
let d = [];
for (let i = 0; i < product.data.product_list.length; i++) {
let goods = product.data.product_list[i];
for (let o = 0; o < product.data.product_list.length; o++) {
let goods = product.data.product_list[o];
// 最多显示4个
if (i > 3) {
if (o > 3) {
break;
}
d.push(guangProcess.formatProduct(goods, false, true, true, 235, 314, isApp, true, gender));
}
for (id in arr) {
d.forEach(p => {
if (id == p.id) {
p.thumb = helpers.image(arr[id],235,314);
if (arr[p.id]) {
p.thumb = helpers.image(arr[p.id], 235, 314);
reco.push(p);
}
})
}
});
}
// 多个商品
... ... @@ -145,14 +144,13 @@ const _index = (req, res, next) => {
} else if (product.data.product_list.length === 1) { // 单个商品
build.relatedReco = reco[0];
}
data.detail.content.push(build);
guang.detail.content.push(build);
callArticleContent(++i, len, resolve);
});
} else if (art.goodsGroup && art.goodsGroup.data) {// 悬停浮动商品
callArticleContent(++i, len, resolve);
return;
} else if (art.goodsGroup && art.goodsGroup.data) { // 悬停浮动商品
let callArtGoodGroup = (ii, len2) => {
if (ii < len2) {
let goods = art.goodsGroup.data[ii];
let good = {
thumb: helpers.image(goods.cover.cover, 235, 314),
type: guangProcess.getProductIcon(goods.cover.maxSortId),
... ... @@ -164,54 +162,56 @@ const _index = (req, res, next) => {
goods.list.forEach((mini) => {
skns.push(mini.id);
arr[mini.id] = mini.src;
})
});
// 通过SKN获取商品信息
productDetailModel.productInfoBySkns(skns).then((product) => {
if (product.data.product_list) {
let g = [];
product.data.product_list.forEach((goods) => {
g.push(guangProcess.formatProduct(goods, false, true, true, 235, 314, isApp, gender));
product.data.product_list.forEach(_ => {
g.push(guangProcess.formatProduct(_, false, true, true, 235, 314, isApp, gender));
});
for (id in arr) {
g.forEach(p => {
if (id == p.id) {
p.thumb = helpers.image(arr[id],235,314);
if (arr[p.id]) {
p.thumb = helpers.image(arr[p.id], 235, 314);
good.goods.push(p);
}
})
}
});
if (!build.collocation) {
build.collocation = [];
}
build.collocation.push(good);
}
callArtGoodGroup(++ii, len2);
})
});
} else {
data.detail.content.push(build);
guang.detail.content.push(build);
callArticleContent(++i, len, resolve);
}
}
};
callArtGoodGroup(0, art.goodsGroup.data.length);
} else if (art.link) { // 更多商品链接
build.moreLink = art.link.data[0].url;
data.detail.content.push(build);
guang.detail.content.push(build);
callArticleContent(++i, len, resolve);
}
} else {
resolve();
}
}
};
if (detail.getArticleContent) {
return new Promise((resolve, reject) => {
return new Promise((resolve) => {
callArticleContent(0, detail.getArticleContent.length, resolve);
}).then(() => {
// 相关品牌
if (detail.getBrand) {
data.relatedBrand = detail.getBrand;
data.relatedBrand.forEach(brand => {
guang.relatedBrand = detail.getBrand;
guang.relatedBrand.forEach(brand => {
brand.thumb = brand.thumb.replace('http://', '//');
})
});
}
// 相关标签
... ... @@ -219,14 +219,14 @@ const _index = (req, res, next) => {
detail.getArticle.tags.forEach(value => {
if (!isApp) {
value.url = helpers.urlFormat('/tags/index', {
query :value.name
query: value.name
}, 'guang');
}
if (!data.relatedTag) {
data.relatedTag = [];
if (!guang.relatedTag) {
guang.relatedTag = [];
}
data.relatedTag.push(value);
})
guang.relatedTag.push(value);
});
}
// 相关文章
... ... @@ -238,24 +238,24 @@ const _index = (req, res, next) => {
}, 'guang');
}
value.thumb = helpers.image(value.thumb, 279, 175);
if (!data.relatedInfo) {
data.relatedInfo = [];
if (!guang.relatedInfo) {
guang.relatedInfo = [];
}
data.relatedInfo.push(value);
})
guang.relatedInfo.push(value);
});
}
// 分享参数
if (detail.getArticle.cover_image) {
data.shareLink = helpers.urlFormat('/info/index', {
guang.shareLink = helpers.urlFormat('/info/index', {
id: id
}, 'guang');
data.shareTitle = detail.getArticle.article_title;
data.shareDesc = detail.getArticle.article_summary;
if (detail.getArticle.cover_image_type == 1) {
data.shareImg = helpers.image(detail.getArticle.cover_image, 640, 640);
guang.shareTitle = detail.getArticle.article_title;
guang.shareDesc = detail.getArticle.article_summary;
if (detail.getArticle.cover_image_type === 1) {
guang.shareImg = helpers.image(detail.getArticle.cover_image, 640, 640);
} else {
data.shareImg = helpers.image(detail.getArticle.cover_image, 640, 320);
guang.shareImg = helpers.image(detail.getArticle.cover_image, 640, 320);
}
data.title = detail.getArticle.article_title;
data.title_more = true;
... ... @@ -270,18 +270,18 @@ const _index = (req, res, next) => {
title: '逛',
gender: gender,
wechatShare: true,
guang: data
}, parameter));
}, data, parameter));
});
} else {
next();
return;
}
}
}).catch(next);
}
};
module.exports = {
index: _index
}
\ No newline at end of file
};
... ...
... ... @@ -5,14 +5,10 @@
*/
'use strict';
const serviceAPI = global.yoho.ServiceAPI;
const logger = global.yoho.logger;
const helpers = global.yoho.helpers;
const sign = global.yoho.sign
const config = global.yoho.config;
const url = require('url');
const URI_PACKAGE_ARTICLE = 'guang/service/v2/article/';
const URI_PACKAGE_AUTHOR = 'guang/service/v1/author/';
/**
* [逛资讯详情页数据封装]
* @param {[int]} id [内容ID]
... ... @@ -26,7 +22,7 @@ const _package = (id, isApp) => {
getArticleContent: {},
getBrand: {},
getOtherArticle: {}
}
};
// 客户端类型
let clientType = isApp ? 'iphone' : 'h5';
... ... @@ -41,19 +37,19 @@ const _package = (id, isApp) => {
return serviceAPI.get(`${URI_PACKAGE_ARTICLE}getArticle`, param, {
cache: true
}).then(data => {
//接口要判断一下返回状态是否成功,OK,I 服了 YOU
// 接口要判断一下返回状态是否成功,OK,I 服了 YOU
if (data.code !== 200) {
result.code = 400;
return result;
}
let article = data.data;
result['getArticle'] = article;
result.getArticle = article;
let promises = [];
// 获取作者信息
let param = {
param = {
author_id: article.author_id
};
... ... @@ -68,6 +64,7 @@ const _package = (id, isApp) => {
client_type: clientType,
// private_key: sign.privateKey[clientType]
};
// param.client_secret = sign.apiSign(param);
promises.push(serviceAPI.get(`${URI_PACKAGE_ARTICLE}getArticleContent`, param, {
cache: true
... ... @@ -79,6 +76,7 @@ const _package = (id, isApp) => {
client_type: clientType,
// private_key: sign.privateKey[clientType]
};
// param.client_secret = sign.apiSign(param);
promises.push(serviceAPI.get(`${URI_PACKAGE_ARTICLE}getBrand`, param, {
cache: true
... ... @@ -94,6 +92,7 @@ const _package = (id, isApp) => {
limit: 3,
// private_key: sign.privateKey[clientType]
};
// param.client_secret = sign.apiSign(param);
promises.push(serviceAPI.get(`${URI_PACKAGE_ARTICLE}getOtherArticle`, param, {
cache: true
... ... @@ -103,14 +102,14 @@ const _package = (id, isApp) => {
result.getAuthor = datas[0].data;
result.getArticleContent = datas[1].data;
result.getBrand = datas[2].data;
if (datas.length == 4) {
if (datas.length === 4) {
result.getOtherArticle = datas[3].data;
}
return result;
});
});
}
};
module.exports = {
package: _package
}
\ No newline at end of file
};
... ...
{{#if .}} {{!-- 剔除值为false的项 --}}
<div class="good-info" data-id="{{id}}">
<div class="tag-container clearfix">
{{# tags}}
{{# is_new}}
<p class="good-tag new-tag">NEW</p>
{{/ is_new}}
{{# is_advance}}
<p class="good-tag renew-tag">再到着</p>
{{/ is_advance}}
{{# is_discount}}
<p class="good-tag sale-tag">SALE</p>
{{/ is_discount}}
{{# is_yohood}}
<p class="good-tag new-festival-tag">新品节</p>
{{/ is_yohood}}
{{# is_limited}}
<p class="good-tag limit-tag">限量商品</p>
{{/ is_limited}}
{{/ tags}}
</div>
<div class="good-detail-img">
<a class="good-thumb buriedpoint" href="{{url}}" data-bp-id="shop_good_{{thumb}}_0">
<img class="lazy" data-original="{{thumb}}">
</a>
{{# is_soon_sold_out}}
<p class="few-tag">即将售罄</p>
{{/ is_soon_sold_out}}
</div>
<div class="good-detail-text">
<div class="name">
<a href="{{url}}">{{name}}</a>
</div>
<div class="price {{#if students}}student-price{{/if}}">
{{#if students}}
<span class="sale-price {{^price}}no-price{{/price}}">¥{{studentPrice}}</span>
<span class="students-price-tag"></span>
{{#salePrice}}
<span class="market-price">¥{{.}}</span>
{{/salePrice}}
{{^}}
<span class="sale-price {{^price}}no-price{{/price}}">¥{{salePrice}}</span>
{{#price}}
<span class="market-price">¥{{.}}</span>
{{/price}}
{{/if}}
</div>
</div>
</div>
{{/if}}
\ No newline at end of file
... ...
... ... @@ -10,7 +10,6 @@ const comment = require('./consult-comment');
const api = global.yoho.API;
const helpers = global.yoho.helpers;
const sign = global.yoho.sign
const SINGLE_TICKETS_SKN = 51335912; // 展览票
... ... @@ -702,10 +701,11 @@ let _productInfoBySkns = (skns) => {
limit: skns.length,
order: 's_t_desc'
};
return api.get('', param, {
cache: true
});
}
};
module.exports = {
getProductData,
... ...

10.1 KB | W: | H:

22 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
... ... @@ -15,17 +15,17 @@ var pageInIscroll = false;
var hasCollocationBlock = $('.collocation-block').length > 0 ? true : false;
//collocation block variable
// collocation block variable
var thumbWidth = 0,
$fixedThumbContainer = $(''),
$coBlock, $thumbContainer, $thumbs, $prods,
scrollToEl;
scrollToEl,
myScroll,
winW = $(window).width();
var scrollToEl = document.querySelector('#wrapper .collocation-block');
var winW = $(window).width();
scrollToEl = document.querySelector('#wrapper .collocation-block');
var myScroll;
require('../plugin/wx-share')();
... ... @@ -48,7 +48,7 @@ function posCollocationArrow($curCo) {
}
}
//搭配thumb的touch事件句柄
// 搭配thumb的touch事件句柄
function thumbTouchEvt(e) {
var $curCo = $(e.currentTarget),
index = $curCo.index(),
... ... @@ -75,7 +75,7 @@ function thumbTouchEvt(e) {
$curCo.addClass('focus');
//定位arrow
// 定位arrow
posCollocationArrow($curCo);
$prods.not('.hide').addClass('hide');
... ... @@ -106,7 +106,7 @@ function initIscroll() {
var hH = 0,
winH, tcH, cbH, cbTop, fixedThumbDom;
//考虑通用头部的影响:对offset().top以及winH做对应偏移
// 考虑通用头部的影响:对offset().top以及winH做对应偏移
if ($yohoHeader.length > 0) {
hH = $yohoHeader.outerHeight();
}
... ... @@ -176,7 +176,7 @@ function initIscroll() {
});
}
//window onload 后重新refresh iscroll
// window onload 后重新refresh iscroll
window.onload = function() {
myScroll && myScroll.refresh();
};
... ... @@ -186,8 +186,8 @@ $('img').on('load', function() {
myScroll && myScroll.refresh();
});
//初始化页面,包括是否使用iscorll初始化页面
//接口暴露在HTML中,使用压缩名
// 初始化页面,包括是否使用iscorll初始化页面
// 接口暴露在HTML中,使用压缩名
(function(useIscroll) {
var isIphone = navigator.userAgent.indexOf('iPhone') > 0 ? true : false;
var $this, $title;
... ... @@ -206,12 +206,12 @@ $('img').on('load', function() {
}
lazyLoad($('.lazy'));
//title mlellipsis
// title mlellipsis
$('.info-list .title, .one-good .reco-name').each(function() {
this.mlellipsis(2);
});
//offset.left约等于marginLeft的值则表示介绍被换行,则清除intro的paddingTop让其更靠近头像和作者名
// offset.left约等于marginLeft的值则表示介绍被换行,则清除intro的paddingTop让其更靠近头像和作者名
if ($authorIntro.offset() && (parseInt($authorIntro.offset().left, 10) ===
parseInt($authorIntro.css('margin-left'), 10))) {
$authorIntro.css('padding-top', 0);
... ... @@ -225,7 +225,7 @@ $('img').on('load', function() {
}
}
//有搭配模块,iphone使用iscroll初始化滚动并有固定的搭配栏,其他的没有
// 有搭配模块,iphone使用iscroll初始化滚动并有固定的搭配栏,其他的没有
if (hasCollocationBlock) {
$coBlock = $('.collocation-block');
$thumbContainer = $coBlock.children('.thumb-container');
... ... @@ -239,13 +239,13 @@ $('img').on('load', function() {
.after($thumbContainer.clone().addClass('fixed-thumb-container fixed-bottom'))
.next('.thumb-container');
//load img of fixed thumb container
// load img of fixed thumb container
lazyLoad($fixedThumbContainer.find('.lazy'), {
event: 'sporty'
});
}
//Init Arrow Position
// Init Arrow Position
posCollocationArrow($thumbs.filter('.focus'));
$thumbContainer.delegate('.thumb', 'touchend', thumbTouchEvt);
... ... @@ -259,4 +259,4 @@ $('img').on('load', function() {
if (pageInIscroll) {
initIscroll();
}
})(false);
\ No newline at end of file
}(false));
... ...
/* global wx */
/**
* 微信分享
* @author: xuqi<qi.xu@yoho.cn>
* @date: 2015/10/30
*/
var $ = require('yoho-jquery');
module.exports = function() {
var $ = require('yoho-jquery');
var _weChatInterface = '/life/getSignPackage';
$.getJSON(_weChatInterface + '?pageurl=' +
encodeURIComponent(location.href.split('#')[0]) + '&callback=?', function (json) {
encodeURIComponent(location.href.split('#')[0]) + '&callback=?', function(json) {
var _appId, _timestamp, _nonceStr, _signature;
if (!wx) {
return;
}
... ... @@ -68,7 +71,7 @@ module.exports = function() {
}
});
wx.ready(function () {
wx.ready(function() {
var shareTitle = $('#shareTitle').val();
var shareImg = $('#shareImg').val();
var shareDesc = $('#shareDesc').val();
... ...
... ... @@ -116,14 +116,14 @@
background: #fff;
.good-list {
padding-left:15px;
padding-left: 15px;
}
}
.thumb-container {
padding-top: 30px;
padding-left: 20px;
background: transparent resolve('guang/thumb-container-bg.png') no-repeat;
background: transparent resolve("guang/thumb-container-bg.png") no-repeat;
background-size: 200% 100%;
&.fixed-top {
... ... @@ -138,7 +138,7 @@
left: 0;
right: 0;
bottom: 0;
background: rgba(255,255,255,0.9);
background: rgba(255, 255, 255, 0.9);
}
&.absolute {
... ... @@ -345,7 +345,7 @@
.brand-list {
border-top: 1px solid #e0e0e0;
border-bottom: 1px solid #e0e0e0;
padding: 30px 0 30px;
padding: 30px 0;
background: #fff;
}
... ... @@ -375,13 +375,12 @@
display: block;
max-width: 158px;
max-height: 94px;
vertical-align: middle;
margin: 0 auto;
}
}
.brand-name {
margin: 10px 0 0 0;
margin: 10px 0 0;
line-height: 24px;
font-size: 18px;
color: #babac2;
... ... @@ -404,7 +403,7 @@
position: absolute;
height: 40px;
width: 40px;
background: resolve('guang/tag.png') no-repeat;
background: resolve("guang/tag.png") no-repeat;
background-size: 100% 100%;
top: 35px;
left: 20px;
... ... @@ -463,14 +462,14 @@
}
}
.title, .publish-time {
.title,
.publish-time {
float: left;
width: 360px;
margin-left: 30px;
line-height: 40px;
color: #444;
font-size: 28px;
}
.publish-time {
... ...
... ... @@ -150,19 +150,20 @@ const _formatArticle = (articleData, showTag, isApp, showAuthor, uid, reqQuerySt
*/
const _getProductIcon = (type) => {
const icons = {
'1': 'cloth',
'3': 'pants',
'4': 'dress',
'6': 'shoe',
'7': 'bag',
'10': 'lamp',
'241': 'headset',
'8': 'watch',
'360': 'swim-suit',
'308': 'under'
1: 'cloth',
3: 'pants',
4: 'dress',
6: 'shoe',
7: 'bag',
10: 'lamp',
241: 'headset',
8: 'watch',
360: 'swim-suit',
308: 'under'
};
return icons[type] || '';
}
};
/**
* [根据性别获取]
... ... @@ -178,7 +179,8 @@ const _getGenderByCookie = (gender) => {
default: // 其它
return '1,2,3';
}
}
};
/**
* [根据性别来决定 默认图片获取字段 如果是 2、3]
*
... ... @@ -193,13 +195,15 @@ const _procProductImg = (images, gender) => {
let imgUrl = images.images_url || '';
let cover1 = images.cover_1 || '';
let cover2 = images.cover_2 || '';
gender = _getGenderByCookie(gender);
if (gender === '2,3') {
return cover2 || (cover1 || imgUrl);
} else {
return cover1 || (cover2 || imgUrl);
}
}
};
/**
* 格式化商品信息
*
... ... @@ -221,6 +225,7 @@ const _formatProduct = (productData, showTags, showNew, showSale, width, height,
}
productData.sales_price = productData.sales_price || '';
productData.market_price = productData.market_price || '';
// 市场价和售价一样,则不显示市场价
if (parseInt(productData.market_price) === parseInt(productData.sales_price)) {
productData.market_price = false;
... ... @@ -238,6 +243,7 @@ const _formatProduct = (productData, showTags, showNew, showSale, width, height,
break;
}
}
// 如果还未赋值,则取第一个skc产品的默认图片
if (!flag) {
productData.default_images = _procProductImg(productData.goods_list[0], gender);
... ... @@ -251,14 +257,17 @@ const _formatProduct = (productData, showTags, showNew, showSale, width, height,
price: productData.market_price || false,
salePrice: productData.sales_price
};
if (showPoint) {
result.price = result.price + '.00';
result.salePrice = result.salePrice + '.00';
}
// TODO student price
result.studentPrice = parseInt(productData.sales_price * 100 * 0.9) / 100;
result.is_soon_sold_out = (productData.is_soon_sold_out === 'Y');
let url = helpers.urlFormat(`/product/pro_${productData.product_id}_${productData.goods_list[0].goods_id}/${productData.cn_alphabet}.html`);
result.url = url.replace('http://', '//');
// APP访问需要加附加的参数
... ... @@ -290,7 +299,7 @@ const _formatProduct = (productData, showTags, showNew, showSale, width, height,
// }
return result;
}
};
module.exports = {
... ...