Authored by 徐祁xuqi

Merge branch 'feature/zookeeper' of http://git.yoho.cn/fe/yohobuy-node into feature/zookeeper

Conflicts:
	app.js
	package.json
... ... @@ -13,6 +13,8 @@ const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const favicon = require('serve-favicon');
const session = require('yoho-express-session');
const _ = require('lodash');
const fp = require('lodash/fp');
const memcached = require('connect-memcached');
const hbs = require('express-handlebars');
... ... @@ -27,6 +29,11 @@ const MemcachedStore = memcached(session);
// 全局注册library
yohoLib.global(config);
const helpers = global.yoho.helpers;
// NOTE: 这里修改了图片质量的参数
helpers.image = _.flow(helpers.image, fp.replace(/\/quality\/\d*$/, '/quality/90'));
global.middleware = path.resolve('./doraemon/middleware');
global.utils = path.resolve('./utils');
... ...
... ... @@ -173,7 +173,7 @@ const local = {
return `${config.siteUrl}/home`;
}
}());
console.log(user.uid);
AuthHelper.syncUserSession(user.uid, req, res).then(() => {
res.json({
code: 200,
... ...
... ... @@ -17,10 +17,10 @@ const changeFavoriteBrand = (req, res, next) => {
if (uid && brandId) {
brandService.changeAsync(uid, brandId).then(result => {
res.json(result);
return res.json(result);
}).catch(next);
} else if (!uid) {
res.json({
return res.json({
code: 403,
message: '用户ID不存在',
data: {
... ... @@ -28,13 +28,29 @@ const changeFavoriteBrand = (req, res, next) => {
}
});
} else {
res.json({
return res.json({
code: 400,
message: '操作失败'
});
}
};
const isFavoriteBrand = (req, res, next) => {
let uid = req.user.uid || '';
let brandId = req.query.brandId;
if (uid && brandId) {
brandService.isFavoriteAsync(uid, brandId).then(result => {
return res.json(result);
}).catch(next);
} else {
return res.json({
code: 400,
message: '状态失败'
});
}
};
const collectProduct = (req, res, next) => {
let uid = req.user.uid || '';
let pid = req.body.productId;
... ... @@ -43,8 +59,7 @@ const collectProduct = (req, res, next) => {
if (uid && pid) {
switch (type) {
case 'add':
{
productService.createAsync(uid, pid)
productService.createAsync(uid, pid)
.then(result => {
if (result.code === 413) {
result.message = '该商品已经收藏';
... ... @@ -53,22 +68,17 @@ const collectProduct = (req, res, next) => {
res.json(result);
})
.catch(next);
break;
}
break;
case 'cancel':
{
productService.deleteAsync(uid, pid)
productService.deleteAsync(uid, pid)
.then(result => res.json(result))
.catch(next);
break;
}
break;
default:
{
res.json({
code: 400,
message: '错误类型'
});
}
res.json({
code: 400,
message: '错误类型'
});
}
} else if (!uid) {
res.json({
... ... @@ -114,8 +124,26 @@ const collectShop = (req, res, next) => {
}
};
const isFavShop = (req, res, next) => {
let uid = req.user.uid;
let shopId = req.body.shopId;
if (!uid || !shopId) {
return res.json({
code: 400,
message: '未收藏'
});
}
fav.getFavStatus(uid, shopId, 'shop').then(result => {
return res.json(result);
}).catch(next);
};
module.exports = {
changeFavoriteBrand,
collectProduct,
collectShop
collectShop,
isFavShop,
isFavoriteBrand
};
... ...
... ... @@ -107,3 +107,19 @@ exports.userAcquireStatus = (req, res, next) => {
}).catch(next);
};
/**
* 学生返币专享页面
* @param {[type]} req [description]
* @param {[type]} res [description]
* @return {[type]} [description]
*/
exports.list = (req, res, next) => {
let resData = {};
studentsModel.getStudentsList(req.query, req.yoho.channel).then(result => {
Object.assign(resData, result);
res.render('list/index', resData);
}).catch(next);
};
... ...
... ... @@ -56,8 +56,8 @@ const indexAsync = pid => {
marketPrice: cur.product.productPriceBo.formatMarketPrice,
productName: cur.product.productName,
href: helpers.getUrlBySkc(
_.head(goods.goodsImagesList).productId,
_.head(goods.goodsImagesList).goodsId,
_.get(goods, 'goodsImagesList[0].productId', ''),
_.get(goods, 'goodsImagesList[0].goodsId', ''),
cur.product.cnAlphabet
)
};
... ...
... ... @@ -67,7 +67,7 @@ const _getProductIntroAsync = (productId, productSkn) => {
* pid : product id
* bid : brand id
*/
const _getProductFavoriteDataAsync = (uid, pid, bid) => {
const _getProductFavoriteDataAsync = (uid, pid) => {
return co(function*() {
let result = {
product: false,
... ... @@ -84,23 +84,14 @@ const _getProductFavoriteDataAsync = (uid, pid, bid) => {
requestApi.product = favoriteProductService.isFavoriteAsync(uid, pid);
}
if (bid) {
requestApi.brand = favoriteBrandService.isFavoriteAsync(uid, bid);
}
let requestData = yield Promise.props(requestApi);
let productData = requestData.product;
let brandData = requestData.brand;
if (productData) {
result.product = productData.code === 200 && productData.data ? true : false;
}
if (brandData) {
result.brand = brandData.code && brandData.code === 200 ? true : false;
}
return result;
})();
};
... ... @@ -1072,11 +1063,9 @@ const _detailDataPkg = (origin, uid, vipLevel, cookies) => {
result.goCartUrl = helpers.urlFormat('/shopping/cart');
let brandId = propOrigin('brand_info.brand_id', 0);
let requestApi = {
addition: _getProductAdditionInfoAsync(origin), // 预处理所有的数据
fav: _getProductFavoriteDataAsync(uid, result.productId, brandId), // 处理收藏喜欢数据
fav: _getProductFavoriteDataAsync(uid, result.productId), // 处理收藏喜欢数据
promotion: productAPI.getPromotionAsync(result.skn) // 打折信息
};
... ...
... ... @@ -9,6 +9,23 @@
const api = global.yoho.API;
/**
* 是否收藏API
* @function cancelFavAsync
* @param { number } uid 用户uid
* @param { number } id 收藏id
* @param { string } type 类型 product--商品 brand--品牌 shop--店铺
* @return { Object } 收藏状态
*/
const isFavAsync = (uid, id, type) => {
return api.get('', {
method: 'app.favorite.isFavorite',
id: id,
uid: uid,
type: type
});
};
/**
* 收藏API
* @function addFavAsync
* @param { number } uid 用户uid
... ... @@ -43,6 +60,7 @@ const cancelFavAsync = (uid, id, type) => {
};
module.exports = {
isFavAsync, // 是否收藏
addFavAsync, // 收藏
cancelFavAsync // 取消收藏
};
... ...
... ... @@ -56,7 +56,12 @@ const toggleFavShop = (shopId, uid, isadd) => {
}
};
const getFavStatus = (uid, id, type) => {
return favAPI.isFavAsync(uid, id, type);
};
module.exports = {
getFavStatus, // 收藏状态
toggleFavProduct, // 收藏商品
toggleFavBrand, // 收藏品牌
toggleFavShop // 收藏店铺
... ...
... ... @@ -902,6 +902,7 @@ const getBaseShopData = (params, extra, channel, shopId) => {
shopIntro: `/about?shopId=${shopId}`,
coled: _.get(result[2], 'data.is_favorite', 'N') === 'Y'
});
_.set(resData, 'brand.shopBanner', decorator.shopTopBannerBase);
_.unset(resData, 'brand.brandBanner');
... ... @@ -914,6 +915,7 @@ const getBaseShopData = (params, extra, channel, shopId) => {
if (result[2].code === 200) {
let shopName = _.get(result[2], 'data.shop_name', '');
_.set(resData, 'brand.shopBanner.shopName', shopName);
_.set(resData, 'brand.pathNav[2]', {
name: shopName,
pathTitle: shopName
... ...
... ... @@ -525,5 +525,7 @@ module.exports = {
getShopDecorator,
getArticleByBrand,
getShopList,
getBrands4Filter
getBrands4Filter,
getProductListOrig,
getSearchCackeKey
};
... ...
... ... @@ -72,7 +72,7 @@ const _signboard = data => {
});
return {
title: result[0].title || '',
title: '',
list: result
};
};
... ...
... ... @@ -6,6 +6,10 @@
'use strict';
const api = global.yoho.API;
const config = require('../../../config/common');
const searchApi = require('./search-api');
const cache = global.yoho.cache;
const logger = global.yoho.logger;
/**
* 获取完成认证学生总数
... ... @@ -115,3 +119,58 @@ exports.userAcquireStatus = (uid, couponIds) => {
return api.get('', finalParams);
};
/**
* 获取学生专享商品列表
* @return
*/
exports.getStudentsProduct = (params) => {
let finalParams = {
method: 'app.student.rebate',
sales: 'Y',
stocknumber: 1,
need_filter: 'yes',
limit: 60
};
Object.assign(finalParams, params);
if (!config.useCache) {
return searchApi.getProductListOrig(finalParams);
} else {
let cKey = searchApi.getSearchCackeKey(finalParams);
return cache.get(cKey).catch().then(cdata => {
let hasCache = false;
if (cdata) {
try {
cdata = JSON.parse(cdata);
} catch (e) {
logger.debug('getProductList cache data parse fail.');
}
if (cdata.filter && cdata.standard) {
hasCache = true;
finalParams.need_filter = 'no';
}
}
return searchApi.getProductListOrig(finalParams).then(result => {
if (hasCache && result && result.data) {
Object.assign(result.data, cdata);
} else {
if (result && result.data && result.data.filter) {
cache.set(cKey, Object.assign({}, {
filter: result.data.filter,
standard: result.data.standard
}), 3600);
}
}
return result;
});
});
}
};
... ...
... ... @@ -115,7 +115,7 @@ exports.stuProducts = (data) => {
data[key].market_price = data[key].sales_price;
delete data[key].sales_price;
if (value.student_price) {
Object.assign(data[key], {forStu: true});
Object.assign(data[key], {for_stu: true});
}
});
return products;
... ...
... ... @@ -5,7 +5,7 @@
*/
'use strict';
const utils = '../../../utils';
const api = global.yoho.API;
const queryString = require('querystring');
const _ = require('lodash');
... ... @@ -14,11 +14,13 @@ const studentsApi = require('./students-api');
const stuHandler = require('./students-handler');
const helpers = global.yoho.helpers;
const crypto = global.yoho.crypto;
// const productProcess = require(`${utils}/product-process`);
// const _ = require('lodash');
const headerModel = require('../../../doraemon/models/header');
const serviceApi = global.yoho.ServiceAPI;
const searchApi = require('./search-api');
const productProcess = require(`${utils}/product-process`);
const searchHandler = require('./search-handler');
const needParams = ['query', 'msort', 'misort', 'gender', 'shelveTime'];
// 学生营销资源码
const studentsCode = '989396a17443bf61e3e269702e51ef04'; // h5 a83b7d55324fb65f96c1f85a3387ebd8
... ... @@ -177,3 +179,86 @@ exports.userAcquireStatus = (uid, couponIds) => {
return result;
});
};
/**
* 获取学生返币专享商品列表数据
*/
exports.getStudentsList = (params, channel) => {
let standard = [];
_.forEach(params, (value, key) => {
let s = _.split(key, 'parameter_', 2);
if (s.length > 1) {
standard.push(`${s[1]}_${value}`);
_.unset(params, `${key}`);
}
});
if (standard.length) {
params.standard = standard.join(',');
}
let searchParams = searchHandler.getSearchParams(params);
// 调用接口
let apiMethod = [
headerModel.requestHeaderData(channel),
searchApi.getSortList(Object.assign({}, {msort: '', misort: ''})),
studentsApi.getStudentsProduct(searchParams)
];
return Promise.all(apiMethod).then(result => {
let finalResult = {
module: 'product',
page: 'list',
headerData: Object.assign(result[0].headerData, {
header: true
}),
list: {
leftContent: {}
}
};
// 获取左侧类目数据
if (result[1].code === 200) {
let dps = {};
_.forEach(needParams, (value) => {
if (params[value]) {
dps[value] = params[value];
}
});
finalResult.list = Object.assign(
searchHandler.handlePathNavData(result[1].data.sort, params, 'sort', channel), {
leftContent: searchHandler.handleSortData(result[1].data.sort, dps)
});
}
// 获取商品数据和顶部筛选条件
if (result[2].code === 200) {
//删掉student_price,不让页面显示
_.forEach(result[2].data.product_list, goods => {
delete goods.student_price;
});
Object.assign(finalResult.list, {
filters: searchHandler.handleFilterDataAll(result[2].data, params),
opts: searchHandler.handleOptsData(params, result[2].data.total, result[2].data.filter),
totalCount: result[2].data.total,
footPager: searchHandler.handlePagerData(result[2].data.total, params),
goods: productProcess.processProductList(result[2].data.product_list,
Object.assign({showDiscount: false}, params, {
from: {type: 'list', params: params}
})),
hasNextPage: searchHandler.handleNextPage(params, result[2].data.total),
// 最近浏览记录
latestWalk: 6
});
}
finalResult.criteo = {skn: searchHandler.getCriteo(_.get(finalResult.list, 'goods'))};
return Object.assign({}, finalResult);
});
};
... ...
... ... @@ -61,6 +61,7 @@ router.post('/index/favoriteBrand', favorite.changeFavoriteBrand);// 收è—å“ç‰
router.post('/item/togglecollect', favorite.collectProduct); // 收藏商品
router.get('/detail/header', detail.productHeader); // 价格数据重新获取接口
router.get('/detail/return', detail.detailReturn);// 特殊商品退换货
router.get('/index/isfav', favorite.isFavoriteBrand);// 品牌收藏状态
// 搜索
router.get('/search/index', search.index);
... ... @@ -84,6 +85,7 @@ router.get('/index/about', list.brandAbout);
router.get('/shoplist', list.shopList); // 店铺列表页
router.post('/shop/togglecollect', favorite.collectShop); // 店铺收藏
router.post('/index/isFavoriteShop', favorite.isFavShop); // 判断用户是否收藏品牌
// 品牌页水牌
router.post('/index/getNodeContent', list.getNodeContent);
... ... @@ -101,5 +103,6 @@ router.get('/students/schoolList', students.schoolList); // 学校地区
router.get('/students/eduLevel', students.eduLevel); // 学校地区
router.get('/students/verify', students.verify); // 身份验证
router.get('/students/userAcquireStatus', students.userAcquireStatus); // 获取优惠券领取状态
router.get('/students/list', students.list); // 获取优惠券领取状态
module.exports = router;
... ...
... ... @@ -30,6 +30,7 @@ module.exports = {
activity: '//activity.yohobuy.com',
index: '//yohobuy.com'
},
zookeeperServer: '192.168.102.168:2188',
useOneapm: false,
useCache: false,
memcache: {
... ...
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{{title}}</title>
<meta name="keywords" content="{{keywords}}">
<meta name="description" content="{{description}}">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<meta http-equiv="cleartype" content="on">
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta content="telephone=no" name="format-detection" />
<meta content="email=no" name="format-detection" />
<link rel="dns-prefetch" href="//cdn.yoho.cn">
<link rel="dns-prefetch" href="//static.yohobuy.com">
<link rel="dns-prefetch" href="//img12.static.yhbimg.com">
<link rel="dns-prefetch" href="//img13.static.yhbimg.com">
{{#if devEnv}}
<link rel="stylesheet" href="//localhost:5002/css/index.css">
{{^}}
<link rel="stylesheet" href="//cdn.yoho.cn/yohobuy-node/{{version}}/index.css">
{{/if}}
</head>
<body>
{{> header}}
{{> common/simple-header}}
{{#if pageErr}}
{{> 404}}
{{^}}
{{{body}}}
{{/if}}
{{> footer}}
{{#if devEnv}}
<script src="//localhost:5002/libs.js"></script>
<script src="//localhost:5002/{{module}}.{{page}}.js"></script>
{{^}}
<script src="//cdn.yoho.cn/yohobuy-node/{{version}}/libs.js"></script>
<script src="//cdn.yoho.cn/yohobuy-node/{{version}}/{{module}}.{{page}}.js"></script>
{{> analysis}}
{{/if}}
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{{title}}</title>
<meta name="keywords" content="{{keywords}}">
<meta name="description" content="{{description}}">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<meta http-equiv="cleartype" content="on">
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta content="telephone=no" name="format-detection" />
<meta content="email=no" name="format-detection" />
<link rel="dns-prefetch" href="//cdn.yoho.cn">
<link rel="dns-prefetch" href="//static.yohobuy.com">
<link rel="dns-prefetch" href="//img12.static.yhbimg.com">
<link rel="dns-prefetch" href="//img13.static.yhbimg.com">
{{#if devEnv}}
<link rel="stylesheet" href="//localhost:5002/css/index.css">
{{^}}
<link rel="stylesheet" href="//cdn.yoho.cn/yohobuy-node/{{version}}/index.css">
{{/if}}
</head>
<body>
{{> header}}
{{> common/simple-header}}
{{#if pageErr}}
{{> 404}}
{{^}}
{{{body}}}
{{/if}}
{{> footer}}
{{#if devEnv}}
<script src="//localhost:5002/libs.js"></script>
<script src="//localhost:5002/{{module}}.{{page}}.js"></script>
{{^}}
<script src="//cdn.yoho.cn/yohobuy-node/{{version}}/libs.js"></script>
<script src="//cdn.yoho.cn/yohobuy-node/{{version}}/{{module}}.{{page}}.js"></script>
{{> analysis}}
{{/if}}
</body>
</html>
... ...
{
"name": "yohobuy-node",
"version": "5.0.7",
"version": "5.0.11",
"private": true,
"description": "A New Yohobuy Project With Express",
"repository": {
... ...
... ... @@ -809,6 +809,19 @@ window.fetchReturn = fetchReturn;
$('.main').html(result);
bindEvent.fire();
});
$.ajax({
type: 'GET',
url: '/product/index/isfav',
data: {
brandId: $('#brand-favour').data('id')
}
}).then(function(result) {
if (result.code === 200) {
$('#brand-favour').addClass('coled');
}
});
}());
// 数据懒加载
... ...
... ... @@ -72,3 +72,22 @@ if ($brandFavor && $brandFavor.length) {
}
});
}
// 页面进入更新收藏状态
if ($shopFavor && $shopFavor.length) {
$.ajax({
type: 'POST',
url: '/product/index/isFavoriteShop',
data: {
shopId: shopId
}
}).then(function(data) {
if (data.code === 200 && data.data) {
// 已收藏
$shopFavor.find('i').addClass('coled');
return;
}
$shopFavor.find('i').removeClass('coled');
});
}
... ...
... ... @@ -11,12 +11,16 @@ var product = require('./index/product');
var $shopIntro = $('.shop-intro'),
$shopCollect = $('.shop-collect'),
$colloectIcon = $shopCollect.find('.shop-collect-ico'),
$colloectText = $shopCollect.find('.shop-collect-text'),
$searchForm = $('#shop-search-form'),
$sliderLeft = $('.slider-left'),
$allGoods = $('.all-goods'),
$fixedArea = $allGoods.find('.fixed-area'),
fixedAreaTop = $fixedArea.offset() ? $fixedArea.offset().top : 0;
var shopId = $shopCollect.data('id');
// Pjax
require('yoho-jquery-pjax');
... ... @@ -36,6 +40,26 @@ if ($sliderLeft.length) {
$sliderLeft.slider();
}
if ($shopCollect && $shopCollect.length) {
$.ajax({
type: 'POST',
url: '/product/index/isFavoriteShop',
data: {
shopId: shopId
}
}).then(function(data) {
if (data.code === 200 && data.data) {
// 已收藏
$colloectIcon.addClass('on');
$colloectText.html('已收藏');
return;
}
$colloectIcon.removeClass('on');
$colloectText.html('收藏');
});
}
$shopIntro.on('click', function() {
$('.pop-shop-intro').show();
$('.mask').show();
... ... @@ -53,9 +77,7 @@ $('.shop-query-submit').on('click', function() {
// 收藏店铺
function colloectAction() {
var $colloectIcon = $shopCollect.find('.shop-collect-ico'),
$colloectText = $shopCollect.find('.shop-collect-text'),
isFavorite = $colloectIcon.hasClass('on'),
var isFavorite = $colloectIcon.hasClass('on'),
needColloect = window.cookie('needColloect');
$.ajax({
... ... @@ -64,7 +86,7 @@ function colloectAction() {
data: {
isFavorite: isFavorite ? 0 : 1,
needColloect: needColloect,
shopId: $shopCollect.data('id')
shopId: shopId
},
success: function(res) {
if (res.code === 200) {
... ...
... ... @@ -448,7 +448,7 @@ $couponDia.on('click', function() {
$rightDia.on('click', function() {
var cont = '<h3 class="dia-title">特权详细说明</h3>' +
'<p>权益1:新品立享9折</p>' +
'<p>学生购买原价新品时,可立即享受9折优惠,与VIP折扣不可同时享受。</p><br>' +
'<p>学生购买指定原价新品时,可立即享受9折优惠,与VIP折扣不可同时享受。</p><br>' +
'<p>权益2:每1元返1个有货币</p>' +
'<p>学生购买指定商品时,以商品的实际成交金额计算,每1元返1个有货币;</p>' +
'<p>返有货币时间:确认收货7日后,系统将自动将对应数量的有货币返至购买账户;</p>' +
... ... @@ -662,7 +662,7 @@ $(function() {
var rightsFirst = '<div class="item-content hide">' +
'<p class="item-title">新品立享9折</p>' +
'<p>学生购买原价新品时,可立即享受9折优惠,与VIP折扣不可同时享受。</p></div>';
'<p>学生购买指定原价新品时,可立即享受9折优惠,与VIP折扣不可同时享受。</p></div>';
var rightsSecond = '<div class="item-content hide">' +
'<p class="item-title">每1元返1个有货币</p>' +
... ... @@ -824,10 +824,12 @@ $(function() {
$('#stuRights .stu-rights-item:eq(0), #stuRights .stu-rights-item:eq(1),' +
'#stuRights .stu-rights-item:eq(2), #stuRights .stu-rights-item:eq(3)').hover(function() {
var content = $(this).find('.item-content');
var gapHeight;
content.removeClass('hide');
let gapHeight = parseInt(content.height(), 10) + 40 - parseInt($(this).height(), 10);
gapHeight = parseInt(content.height(), 10) + 40 - parseInt($(this).height(), 10);
if (gapHeight > 0) {
content.css('margin-top', -(gapHeight) + 'px');
... ...
... ... @@ -57,6 +57,13 @@
width: 1150px;
margin: 0 auto;
.shop-name {
margin-left: 60px;
font-size: 32px;
float: left;
border: none;
}
.shop-favor {
margin-right: 60px;
}
... ...
... ... @@ -116,9 +116,10 @@
.stu-rights-item .item-content {
position: absolute;
top: 0;
min-height: 160px;
padding: 20px;
margin-top: 0;
transition: margin-top 2s linear;
transition: margin-top 2.5s linear;
background: rgba(255,255,255,.95);
}
... ...
... ... @@ -16,9 +16,6 @@ const itemFromBase = {
saleSpecial: {domain: 'sale', module: 's'}// sale.yohobuy.com
};
// NOTE: 这里修改了图片质量的参数
helpers.image = _.flow(helpers.image, fp.replace(/\/quality\/\d*$/, '/quality/90'));
/**
* 根据性别来决定 默认图片获取字段 如果是 2、3
*
... ...