Authored by lijing

合5.6

... ... @@ -148,17 +148,6 @@ app.use((req, res, next) => {
req.yoho = {}; // req和res绑定yoho对象,用于传递全局数据, 如req.yoho.channel等
req.app.locals.wap = app.locals.wap; // zookeper对象赋值
// 临时增加错误日志记录
let sendJson = res.json;
res.json = function(...args) {
try {
sendJson(...args);
} catch (e) {
logger.error(`res.json error data: ${JSON.stringify(args)}`);
}
};
next();
});
... ...
... ... @@ -241,7 +241,7 @@ const getPriceGiftList = (promotionIds, promotionType) => {
method: 'app.Shopping.queryPromotionGifts',
promotion_ids: promotionIds
}).then((data) => {
return data.code === 200 ? cartProcess.procPriceGiftData(data.data, promotionType) : void 0;
return data.code === 200 ? cartProcess.procPriceGiftData(data.data, promotionType) : {};
});
};
... ...
... ... @@ -42,7 +42,7 @@ const _packageAd = (params) => {
const _packageList = (channel) => {
return api.get('', {
method: 'app.brand.newBrandList',
method: 'app.brand.allBrandList',
yh_channel: channel
}, {
cache: true,
... ... @@ -172,7 +172,12 @@ const getBrandListByChannel = (channel) => {
name: row.brand_name,
isHot: row.is_hot === 'Y' ? true : false,
isNew: row.is_show_new === 'Y' ? true : false,
url: helpers.urlFormat('/product/index/brand?domain=' + row.brand_domain)
url: parseInt(row.type, 10) !== 3 ? helpers.urlFormat('/product/index/brand', {
domain: row.brand_domain,
shopType: row.type
}) : helpers.urlFormat('/product/global/list/', {
brand: row.global_brand_id
})
});
});
resu.brandList.push(obj);
... ... @@ -190,7 +195,10 @@ const getBrandListByChannel = (channel) => {
obj.list.push({
brandName: newList[key].brand_name,
url: helpers.urlFormat('/product/index/brand?domain=' + newList[key].brand_domain),
url: helpers.urlFormat('/product/index/brand', {
domain: newList[key].brand_domain,
shopType: newList[key].type
}),
img: helpers.image(newList[key].brand_ico, 186, 115),
});
resu.newBrandWall.push(obj);
... ... @@ -208,7 +216,10 @@ const getBrandListByChannel = (channel) => {
obj.list.push({
brandName: hotList[key].brand_name,
url: helpers.urlFormat('/product/index/brand?domain=' + hotList[key].brand_domain),
url: helpers.urlFormat('/product/index/brand', {
domain: hotList[key].brand_domain,
shopType: hotList[key].type
}),
img: helpers.image(hotList[key].brand_ico, 186, 115),
});
resu.recommandBrandWall.push(obj);
... ...
... ... @@ -201,7 +201,7 @@ const packageData = (id, isApp, isWeixin, channel, isShare) => {
return Promise.all(promises).then(datas => {
let getArticleContent = {};
let getArticleContent = [];
if (datas) {
if (datas[1]) {
... ...
... ... @@ -10,10 +10,12 @@ const passport = require('passport');
// const md5 = require('yoho-md5');
const uuid = require('uuid');
const co = Promise.coroutine;
const cookie = global.yoho.cookie;
const helpers = global.yoho.helpers;
const log = global.yoho.logger;
const config = global.yoho.config;
const cache = global.yoho.cache;
const utils = require(global.utils);
const RegService = require('../models/reg-service');
const AuthHelper = require('../models/auth-helper');
... ... @@ -122,21 +124,10 @@ const local = {
req.session.captchaValidCount = 5;
}
// 先清除cookie
// res.clearCookie('LE' + md5('_LOGIN_EXPIRE'), {
// domain: 'yohobuy.com'
// });
// 设置登录有效时间30分钟, 防机器刷,cache不稳定,改为cookie
// res.cookie('LE' + md5('_LOGIN_EXPIRE'), (new Date()).getTime() / 1000 + 1800);
// 170406 账户密码方式登录可以选择是否开启验证码,默认开关是关闭状态,此时开启验证码,开关开启,无需验证
let captchaShow = _.get(req.app.locals.wap, 'close.loginValidation', false);
res.render('login', {
width750: true,
loginIndex: true, // 模板中使用JS的标识
captchaShow: !captchaShow, // 170306 因为暴力破解密码问题,要求每次都展示验证码
captchaShow: req.yoho.captchaShow,
backUrl: 'javascript:history.go(-1)', // eslint-disable-line
showHeaderImg: true, // 控制显示头部图片
isPassportPage: true, // 模板中模块标识
... ... @@ -166,22 +157,11 @@ const local = {
req.session.captchaValidCount = 5;
}
// 先清除cookie
// res.clearCookie('LE' + md5('_LOGIN_EXPIRE'), {
// domain: 'yohobuy.com'
// });
// 设置登录有效时间30分钟, 防机器刷,cache不稳定,改为cookie
// res.cookie('LE' + md5('_LOGIN_EXPIRE'), (new Date()).getTime() / 1000 + 1800);
// 170406 账户密码方式登录可以选择是否开启验证码,默认开关是关闭状态,此时开启验证码,开关开启,无需验证
let captchaShow = _.get(req.app.locals.wap, 'close.loginValidation', false);
res.render('international', {
width750: true,
backUrl: 'javascript:history.go(-1)', // eslint-disable-line
loginInternational: true, // 模板中使用JS的标识
captchaShow: !captchaShow, // 170306 因为暴力破解密码问题,要求每次都展示验证码
captchaShow: req.yoho.captchaShow,
isPassportPage: true, // 模板中模块标识
headerText: '登录',
areaCode: '+86', // 默认区号
... ... @@ -211,6 +191,8 @@ const local = {
captchaShow: true
};
cache.set(`loginErrorIp:${req.yoho.clientIp}`, true, 3600).catch(log.error);
res.json(obj);
} else {
let refer = req.cookies.refer;
... ... @@ -406,6 +388,36 @@ exports.user = function(req, res, next) {
res.jsonp(result);
};
/**
* 中间件
* 根据用户登录是否成功决定是否展示验证码
*/
exports.loginShowCaptchaByIp = function(req, res, next) {
// 总开关状态
req.yoho.captchaShow = !_.get(req.app.locals.wap, 'close.loginValidation', false);
// 开关打开,不走任何验证逻辑
if (!req.yoho.captchaShow) {
return next();
} else {
req.yoho.captchaShow = false;
}
co(function*() {
let hasErrorLog = yield cache.get(`loginErrorIp:${req.yoho.clientIp}`);
log.info(`Pagerender clientip ${req.yoho.clientIp} status is ` + hasErrorLog);
if (hasErrorLog) {
req.yoho.captchaShow = true;
}
next();
})().catch(function(e) {
req.yoho.captchaShow = true;
next();
});
};
exports.common = common;
exports.local = local;
exports.wechat = wechat;
... ...
... ... @@ -7,6 +7,9 @@
'use strict';
const _ = require('lodash');
const config = global.yoho.config;
const co = Promise.coroutine;
const cache = global.yoho.cache;
const log = global.yoho.logger;
const geetest = require('./geetest');
const captcha = require('./captcha');
... ... @@ -20,20 +23,44 @@ const check = (req, res, next) => {
return next();
}
// 170406 采用账号密码方式登录验证码可以配置关闭,默认开关是关闭状态,这时需要验证,开关开启,无需验证
if (_.get(req.app.locals.wap, 'close.loginValidation', false) && req.path === '/passport/login/auth') {
return next();
}
// 默认取配置总开关来决定是否展示验证码
req.yoho.captchaShow = !_.get(req.app.locals.wap, 'close.loginValidation', false);
// 使用极验证
let useGeetest = !_.get(req.app.locals.wap, 'geetest.validation', false);
co(function* () {
// 如果是账号密码登录,那么需要检查是否登录失败过,登录失败过展示验证码
if (req.path === '/passport/login/auth') {
let hasErrorLog = yield cache.get(`loginErrorIp:${req.yoho.clientIp}`);
// 某次请求极验证调用注册失败,强制使用自有图形验证码
if (req.session.useYohoCaptcha) {
useGeetest = false;
}
log.info(`Check clientip ${req.yoho.clientIp} status is ` + hasErrorLog);
if (hasErrorLog) {
req.yoho.captchaShow = true;
} else {
req.yoho.captchaShow = false;
}
}
return req.yoho.captchaShow;
})().catch(function() {
// memcache 不可用,展示验证码
req.yoho.captchaShow = true;
return req.yoho.captchaShow;
}).then(function() {
// 不是账号密码登录,直接根据配置总开关决定是否需要展示验证码
if (!req.yoho.captchaShow) {
return next();
}
// 使用极验证
let useGeetest = !_.get(req.app.locals.wap, 'geetest.validation', false);
// 某次请求极验证调用注册失败,强制使用自有图形验证码
if (req.session.useYohoCaptcha) {
useGeetest = false;
}
return (useGeetest ? geetest : captcha).validate(req, res, next);
return (useGeetest ? geetest : captcha).validate(req, res, next);
});
};
/**
... ...
... ... @@ -39,10 +39,21 @@ router.get('/emailback.html', back.indexEmailPage);
router.get('/passport/signout/index', login.common.clearCookie, login.local.logout);
// 登录页面
router.get('/passport/login', validateCode.load,
login.common.beforeLogin, login.common.clearCookie, login.local.loginPage);
router.get('/passport/international', validateCode.load,
login.common.beforeLogin, login.common.clearCookie, login.local.international);
router.get('/passport/login',
validateCode.load,
login.common.beforeLogin,
login.common.clearCookie,
login.loginShowCaptchaByIp,
login.local.loginPage
);
router.get('/passport/international',
validateCode.load,
login.common.beforeLogin,
login.common.clearCookie,
login.loginShowCaptchaByIp,
login.local.international
);
// 本地登录
router.post('/passport/login/auth', validateCode.check, login.local.login);
... ...
... ... @@ -44,6 +44,7 @@ const shop = {
let title = '';
let uid = req.user.uid || 0;
let shopEnter;
let shopType = req.query.shopType;
if (req.query.shop_id) {
return shop.shop(req, res, next);
... ... @@ -82,13 +83,13 @@ const shop = {
searchParam.uid = uid;
}
if (req.query.from !== 'search' && brandLogo.type === '2' && brandLogo.shopId) {
if (req.query.from !== 'search' && brandLogo.type === '2' && brandLogo.shopId && shopType !== '1') {
req.query.shop_id = brandLogo.shopId;
shop.shop(req, res, next);
return false;
} else if (req.query.from === 'search') {
} else if (req.query.from === 'search' || shopType === '1') {
return Promise.all([
listModel.getBrandShops(brandId, req),
listModel.getBrandShops(brandLogo.brandDomain, req),
searchModel.getSearchData(searchParam)
]).then(shopResult => {
let brandShop = shopResult[0];
... ... @@ -114,14 +115,16 @@ const shop = {
}
if (brandShop.length > 0 || brandLogo && shopEnter) {
params = _.assign({
brandWay: _.isEmpty(brandShop) ? brandLogo : brandShop,
search: {
default: req.query.query,
default: req.query.query || req.query.domain,
url: helpers.urlFormat('', null, 'search')
}
}, params);
}
return true;
});
} else {
... ... @@ -218,6 +221,12 @@ const shop = {
searchParam.uid = uid;
}
/* 红人店铺直接跳转 */
if (shopInfoResult.is_red_shop) {
shop.redShop(req, res, next);
return false;
}
/* 基础店铺返回程序内的跳转信号,跳转到基础店铺 */
if (shopInfoResult && shopInfoResult.shop_template_type) {
... ...
... ... @@ -891,7 +891,7 @@ const getLimitProductData = (uid, limitProductCode) => {
if (obj.attaches.length > 1) {
obj.attaches.sort((v1, v2) => {
return v1.orderBy - v2.orderBy;
return v2.orderBy - v1.orderBy;
});
}
... ...
... ... @@ -29,17 +29,29 @@ const _processBrandShops = (list) => {
let formatDat = [];
_.forEach(list, item => {
if (item.shop_id) {
if (item.shop_type === 'yoho_shop') {
formatDat.push({
url: helpers.urlFormat('/product/index/brand/', {
shop_id: item.shop_id
}),
thumb: helpers.image(item.shop_logo, 75, 40),
name: item.shop_name
});
} else if (item.shop_type === 'tbl_brand') {
formatDat.push({
url: helpers.urlFormat('/product/global/list/', {
brand: item.global_brand_id
}),
thumb: helpers.image(item.brand_ico, 75, 40),
name: item.brand_name
});
}
});
if (formatDat.length > 2) {
formatDat.moreShop = true;
}
return formatDat;
};
... ... @@ -749,7 +761,8 @@ const getBrandLogoByDomain = (domain) => {
thumb: helpers.image(formatData.brand_ico, 75, 40),
name: formatData.brand_name,
shopId: formatData.shop_id ? formatData.shop_id : 0, // 店铺id
type: formatData.type ? formatData.type : 0
type: formatData.type ? formatData.type : 0,
brandDomain: formatData.brand_domain
};
} else {
return false;
... ... @@ -763,18 +776,18 @@ const getBrandLogoByDomain = (domain) => {
* @param req
* @return array
*/
const getBrandShops = (brandId, req) => {
const getBrandShops = (domain, req) => {
return api.get('', {
method: 'app.shop.queryShopsByBrandId',
brand_id: brandId
method: 'app.search.li',
query: domain
}, {
code: 200,
cache: true
}).then(result => {
if (_.isArray(result.data)) {
if (result.data.shopList && _.isArray(result.data.shopList)) {
let seoResult = _getBrandShopSeo(req.channel, result.data[0], req.query);
return Object.assign(_processBrandShops(result.data), {seoResult: seoResult});
return Object.assign(_processBrandShops(result.data.shopList), {seoResult: seoResult});
} else {
return [];
}
... ...
... ... @@ -123,6 +123,8 @@ const selectHotrank = (yhChannel, gender, sort, tabId, limit, page, notab) => {
}
return formData;
} else {
return {};
}
});
... ...
... ... @@ -12,18 +12,28 @@
</div>
<ul class="search-associate"></ul>
{{/ search}}
{{# brandWay}}
<div class="brand-way" data-shopid="{{shopId}}" data-brandid="{{brandId}}">
<a href={{url}}>
<img class="brand-thumb" src={{image2 thumb q=60}}>
<span class="brand-name">{{name}}</span>
<span class="entry">
进入店铺
<i class="iconfont">&#xe614;</i>
</span>
</a>
{{#if brandWay}}
<div class="brand-way" data-shopid="{{brandWay/shopId}}" data-brandid="{{brandWay/brandId}}">
<div class="brand-enter">
{{# brandWay}}
<a href={{url}}>
<img class="brand-thumb" src={{image2 thumb q=60}}>
<span class="brand-name">{{name}}</span>
<span class="entry">
进入店铺
<i class="iconfont">&#xe614;</i>
</span>
</a>
{{/ brandWay}}
</div>
{{#if brandWay.moreShop}}
<div class="more-shop down">
<span class="iconfont">&#xe616;</span>
</div>
{{/if}}
</div>
{{/ brandWay}}
{{/if}}
<!-- 品牌页面 -->
{{# brandHome}}
<div id="brand-header" class="brand-header" data-id={{id}}>
... ...
... ... @@ -24,6 +24,11 @@
{{# is_presell}}
<p class="good-tag is-presell">预售</p>
{{/ is_presell}}
{{# is_global}}
<p class="good-tag is-global">
<span>{{../tbl_country_name}}</span>
</p>
{{/ is_global}}
{{/ tags}}
</div>
<div class="good-detail-img">
... ... @@ -37,7 +42,7 @@
{{# is_soon_sold_out}}
<p class="few-tag">即将售罄</p>
{{/ is_soon_sold_out}}
{{# is_solded}}
<p class="out-tag">已售罄</p>
{{/ is_solded}}
... ...
... ... @@ -50,7 +50,7 @@
"xml2js": "^0.4.17",
"yoho-express-session": "^2.0.0",
"yoho-md5": "^2.0.0",
"yoho-node-lib": "=0.2.16",
"yoho-node-lib": "=0.2.17",
"yoho-zookeeper": "^1.0.8"
},
"devDependencies": {
... ...
... ... @@ -425,23 +425,15 @@ $reaMask.find('.box-cmp').on('touchend', function() {
return;
}
if (res.code === 200) {
dialog.showDialog({
dialogText: '您的取消订单申请已提交,请耐心等待',
hasFooter: {
leftBtnText: '返回',
rightBtnText: '确定'
}
}, function() {
window.location.href = '/home/orders';
});
return false;
}
if (res.message) {
tip.show(res.message);
}
if (res.code === 200) {
setTimeout(function() {
window.location.href = '/home/orders';
}, 500);
}
}).fail(function() {
tip.show('网络错误');
});
... ...
... ... @@ -259,22 +259,15 @@ $reaMask.find('.box-cmp').on('touchend', function() {
return;
}
if (res.code === 200) {
dialog.showDialog({
dialogText: '您的取消订单申请已提交,请耐心等待',
hasFooter: {
leftBtnText: '返回',
rightBtnText: '确定'
}
}, function() {
window.location.href = '/home/orders';
});
return false;
}
if (res.message) {
tip.show(res.message);
}
if (res.code === 200) {
setTimeout(function() {
window.location.href = '/home/orders';
}, 500);
}
}).fail(function() {
tip.show('网络错误');
});
... ...
... ... @@ -14,7 +14,6 @@ let $account = $('#account'),
$ways = $('#retrive-pwd-ways'),
$captcha = $('#js-img-check'),
useVerify = $captcha.data('userverify'), // 170406 是否使用验证
accPass = false,
pwdPass = false;
... ... @@ -26,16 +25,14 @@ let trim = $.trim;
let showErrTip = tip.show;
let validate = {};
if (useVerify) {
validate = new Validate($captcha, {
useREM: {
rootFontSize: 40,
picWidth: 150
}
});
let validate = new Validate($captcha, {
useREM: {
rootFontSize: 40,
picWidth: 150
}
});
if ($captcha.data('userverify')) {
validate.init();
}
... ... @@ -100,8 +97,13 @@ function loginAuth(params, acc) {
location.href = res.href;
$loginBtn.text('登录成功');
} else {
if (useVerify && data.captchaShow) {
((data.changeCaptcha && validate.type !== 2) && validate.refresh());
$captcha.data('userverify', data.captchaShow);
if (data.captchaShow) {
if (validate.atWorking) {
((data.changeCaptcha && validate.type !== 2) && validate.refresh());
} else {
validate.init();
}
}
showErrTip(data.message);
... ... @@ -161,7 +163,7 @@ $loginBtn.on('touchstart', function() {
password: pwd
};
if (useVerify) {
if ($captcha.data('userverify')) {
validate.getResults().then((result) => {
$loginBtn.text('正在登录...').addClass('disable');
... ...
... ... @@ -200,7 +200,7 @@ function getQueryString(name) {
let r = window.location.search.substr(1).match(reg);
if (r !== null) {
return window.unescape(r[2]);
return decodeURIComponent(r[2]);
}
return null;
}
... ... @@ -577,7 +577,6 @@ if ($brandHeader.data('isbaseshop') === true) {
Object.assign(defaultOpt, {shop_id: $brandHeader.data('id')});
}
$.ajax({
type: 'GET',
url: location.protocol + '//m.yohobuy.com/product/search/filter',
... ... @@ -848,4 +847,14 @@ $('.brand-way a').on('click', function() {
}
});
$('.more-shop').on('click', function() {
if ($(this).hasClass('down')) {
$('.brand-enter').css('max-height', '100%');
$('.more-shop').removeClass('down').find('span').html('&#xe615;');
} else {
$('.brand-enter').removeAttr('style');
$('.more-shop').addClass('down').find('span').html('&#xe616;');
}
});
require('channel/maybe-like')({recpose: 100101, isExecute: true});
... ...
... ... @@ -69,6 +69,21 @@
background-color: #000;
color: #fff;
}
.is-global {
padding: 3px 10px 0 8px;
color: #fff;
background-color: #462e3e;
line-height: 26px;
span {
display: inline-block;
background-image: resolve("product/airplane.png");
background-repeat: no-repeat;
padding-left: 32px;
background-size: auto 95%;
}
}
}
}
... ...
... ... @@ -65,12 +65,16 @@
padding-bottom: 20px;
background: #f4f4f4;
> a {
.brand-enter {
max-height: 160px;
overflow: hidden;
}
a {
display: block;
height: 80px;
line-height: 80px;
padding: 0 20px;
border-bottom: 1px solid #e6e6e6;
border-top: 1px solid #e6e6e6;
font-size: 34px;
background: #fff;
... ... @@ -78,6 +82,10 @@
overflow: hidden;
}
/* a:last-child {
border-bottom: 1px solid #e6e6e6;
} */
span {
font-size: 28px;
overflow: hidden;
... ... @@ -90,21 +98,38 @@
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
position: absolute;
display: inline-block;
/* position: absolute; */
}
.brand-thumb {
display: block;
float: left;
width: 150px;
height: 80px;
margin: 0;
display: inline-block;
}
.entry {
color: #999;
font-size: 28px;
float: right;
display: inline-block;
}
.more-shop {
width: 100%;
height: 40px;
background: #fff;
color: #999;
margin-top: 0;
text-align: center;
span {
position: relative;
top: -6px;
}
}
}
... ...
... ... @@ -103,9 +103,9 @@ exports.processProductList = (list, options) => {
}
// H5 暂时不支持全球购商品,先过滤掉 2017.04.09
if (product.is_global === 'Y') {
return;
}
// if (product.is_global === 'Y') {
// return;
// }
// 商品信息有问题,则不显示
if (!(
... ... @@ -114,7 +114,6 @@ exports.processProductList = (list, options) => {
return;
}
if (product.recommend_type) {
// recommend_type 对应 附加属性
let flagMap = {
... ... @@ -170,7 +169,8 @@ exports.processProductList = (list, options) => {
product.cn_alphabet = productNameProcess(product.cn_alphabet);
}
product.url = helpers.urlFormat(`/product/${product.product_skn}.html`); // 商品url改版 // eslint-disable-line
product.url = product.is_global === 'Y' ? helpers.urlFormat(`/product/global/${product.product_skn}.html`) :
helpers.urlFormat(`/product/${product.product_skn}.html`); // 商品url改版 // eslint-disable-line
// APP访问需要加附加的参数
// 备注:如果以后APP的接口太多,可以把这边参数提取出来,变成一个公共的方法来生成,便于以后管理维护
... ... @@ -191,6 +191,10 @@ exports.processProductList = (list, options) => {
product.is_solded = true;
}
if (product.is_global === 'Y') {
tags.is_global = true;
}
product.is_soon_sold_out = tags.is_soon_sold_out;
}
... ...
... ... @@ -2,10 +2,12 @@
* @Author: Targaryen
* @Date: 2017-03-23 11:02:31
* @Last Modified by: Targaryen
* @Last Modified time: 2017-03-31 16:57:27
* @Last Modified time: 2017-04-12 14:36:15
*/
/* 红人店铺数据处理 */
'use strict';
const _ = require('lodash');
const helpers = global.yoho.helpers;
... ...