Authored by zhangxiaoru

merge master

... ... @@ -73,7 +73,6 @@ app.use(global.yoho.hbs({
helpers: _.assign(global.yoho.helpers, require('./utils/helpers'))
}));
app.use(global.yoho.middleware());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
... ...
... ... @@ -9,7 +9,7 @@ exports.index = function(req, res, next) {
if (!result) {
return next();
}
res.render('feature', {
res.render('feature/index', {
module: 'activity',
page: 'feature',
title: result.name || 'Yoho!Buy有货',
... ... @@ -18,3 +18,17 @@ exports.index = function(req, res, next) {
});
}).catch(next);
};
exports.sidebar = function(req, res, next) {
model.index({
code: req.params.code
}).then((result) => {
if (!result) {
return next();
}
res.render('feature/sidebar', {
content: result,
layout: false
});
}).catch(next);
};
... ...
... ... @@ -16,6 +16,7 @@ const _getProductBySkns = function(productObj) {
producturl: `//m.yohobuy.com/product/pro_${val.product_id}_${goods_id}/${val.cn_alphabet}.html?openby:yohobuy={"action":"go.productDetail","params":{"product_skn":${val.product_skn}}}`, // eslint-disable-line
productimg: helpers.image(val.default_images, 213, 284, 2, 60).replace('quality/80', 'quality/60'),
productname: val.product_name,
vipprice: val.vip_price,
saleprice: val.sales_price,
marketprice: val.sales_price === val.market_price ? '' : val.market_price,
brandname: val.brand_name
... ...
... ... @@ -15,6 +15,7 @@ let _getProduct = function(o) {
product_id: o.product_id,
product_name: o.product_name,
product_skn: o.product_skn,
vip_price: o.vip_price,
market_price: o.market_price,
sales_price: o.sales_price,
cn_alphabet: o.cn_alphabet,
... ...
... ... @@ -373,7 +373,7 @@ const order = (params) => {
code: 200
}).then((result) => {
if (result.data) {
if (result && result.data) {
Object.assign(finalResult, {cancelReason: result.data});
}
return finalResult;
... ... @@ -385,7 +385,7 @@ const order = (params) => {
* @param params
*/
const getOrders = (params) => {
let finalResult = Promise.resolve([]);
let finalResult = [];
if (!params.uid) {
return Promise.resolve([]);
... ...
... ... @@ -229,6 +229,7 @@ router.get('/individuation', individuation.productLst);
// 活动页模版
router.get('/feature/:code.html', feature.index);
router.get('/featuresidebar/:code.html', feature.sidebar);
// 2016 年度账单
router.get('/annual-account', annualAccount.index);
... ...
<div class="feature-page yoho-page">
{{#content.webShare}}
<input id="shareLink" type="hidden" value="{{url}}">
<input id="shareDesc" type="hidden" value="{{content}}">
<input id="shareImg" type="hidden" value="{{pic}}">
<input id="shareTitle" type="hidden" value="{{title}}">
{{/content.webShare}}
{{#content.floors}}
{{#isEqualOr type 'sidebar'}}
{{! 侧悬浮}}
<div class="cexuanfu" id="load_cxf"></div>
{{/isEqualOr}}
{{#isEqualOr type '' 'common_floor' 'fix'}}
{{! 普通楼层 顶悬浮}}
<div {{#if param.anchorname}}id="{{param.anchorname}}"{{/if}} {{#if id}}data-id="{{id}}"{{/if}} class="floor {{type}}"
style="{{#if param.bgcolor}}background-color:{{param.bgcolor}}{{/if}}">
{{#if param.bgimg}}
<img src="{{image2 param.bgimg q=60}}">
{{/if}}
{{#component}}
{{#isEqualOr type 'link'}}
{{! 普通组件}}
<a class="anchor" style="{{styleFormat this percent=1}}" href="{{#if url}}{{url}}{{else}}javascript:void(0);{{/if}}" fp="{{getAnalysis ../this @index}}"></a>
{{/isEqualOr}}
{{#unless content.visiable}}
<div class="over">
<p>此活动已结束</p>
<p>稍后自动跳转更多其他精彩活动...</p>
</div>
{{else}}
{{#content.webShare}}
<input id="shareLink" type="hidden" value="{{url}}">
<input id="shareDesc" type="hidden" value="{{content}}">
<input id="shareImg" type="hidden" value="{{pic}}">
<input id="shareTitle" type="hidden" value="{{title}}">
{{/content.webShare}}
{{#content.floors}}
{{#isEqualOr type 'sidebar'}}
{{! 侧悬浮}}
<div id="sidebar" pageid="{{param.sidebarPageId}}"></div>
{{/isEqualOr}}
{{#isEqualOr type '' 'common_floor' 'fix'}}
{{! 普通楼层 顶悬浮}}
<div {{#if param.anchorname}}id="{{param.anchorname}}"{{/if}} {{#if param.tabname}}tabname="{{param.tabname}}"{{/if}} {{#if id}}data-id="{{id}}"{{/if}} class="floor {{type}}"
style="{{#if param.bgcolor}}background-color:{{param.bgcolor}}{{/if}}">
{{#if param.bgimg}}
{{#isLazyLoad type @index}}
<img class="lazy" data-original="{{image2 param.bgimg q=60}}">
{{else}}
<img src="{{image2 param.bgimg q=60}}">
{{/isLazyLoad}}
{{/if}}
{{#component}}
{{#isEqualOr type 'link'}}
{{! 普通组件}}
<a class="anchor {{#if modalImg}}modalimg{{/if}}" style="{{styleFormat this percent=1}}" href="{{#if url}}{{url}}{{else}}javascript:void(0);{{/if}}" fp="{{getAnalysis ../this @index}}"></a>
{{#if modalImg}}
<div class="modal">
<span class="modal-close"></span>
<img class="modal-img lazy" data-original="{{image2 modalImg q=60}}">
</div>
{{/if}}
{{/isEqualOr}}
{{#isEqualOr type 'coupon'}}
{{! 优惠券}}
<a class="anchor yoho-conpon" style="{{styleFormat this percent=1}}" data-token="{{token}}" href="{{#if url}}{{url}}{{else}}javascript:void(0);{{/if}}" fp="{{getAnalysis ../this @index}}"></a>
{{/isEqualOr}}
{{#isEqualOr type 'coupon'}}
{{! 优惠券}}
<a class="anchor yoho-conpon" style="{{styleFormat this percent=1}}" data-token="{{token}}" href="{{#if url}}{{url}}{{else}}javascript:void(0);{{/if}}" fp="{{getAnalysis ../this @index}}"></a>
{{/isEqualOr}}
{{#isEqualOr type 'yohoCoin'}}
{{! 有货币}}
<a class="anchor yoho-coin" style="{{styleFormat this percent=1}}" data-token="{{token}}" href="{{#if url}}{{url}}{{else}}javascript:void(0);{{/if}}" fp="{{getAnalysis ../this @index}}"></a>
{{/isEqualOr}}
{{#isEqualOr type 'yohoCoin'}}
{{! 有货币}}
<a class="anchor yoho-coin" style="{{styleFormat this percent=1}}" data-token="{{token}}" href="{{#if url}}{{url}}{{else}}javascript:void(0);{{/if}}" fp="{{getAnalysis ../this @index}}"></a>
{{/isEqualOr}}
{{#isEqualOr type 'video'}}
{{! 视频}}
<a class="anchor video-bg" style="{{styleFormat this percent=1}}" href="{{#if url}}{{url}}{{else}}javascript:void(0);{{/if}}" fp="{{getAnalysis ../this @index}}"></a>
<div class="video-android-close hide"></div>
<div class="video-android-bg hide"></div>
<video class="video" controls loop preload="meta" name="media">
<source src="{{videoSrc}}">
</video>
{{/isEqualOr}}
{{#isEqualOr type 'video'}}
{{! 视频}}
<a class="anchor video-bg" style="{{styleFormat this percent=1}}" href="{{#if url}}{{url}}{{else}}javascript:void(0);{{/if}}" fp="{{getAnalysis ../this @index}}"></a>
<div class="video-android-close hide"></div>
<div class="video-android-bg hide"></div>
<video class="video" controls loop preload="meta" name="media">
<source src="{{videoSrc}}">
</video>
{{/isEqualOr}}
{{#isEqualOr type 'marquee' 'swiper'}}
{{! 轮播/滑动}}
<div class="swiper-container {{type}}" data-loop="{{loop}}" {{#if spaceBetween}}data-spacebetween="{{spaceBetween}}"{{/if}} {{#if autoplay}}data-autoplay="{{autoplay}}"{{/if}}>
<div class="swiper-wrapper">
{{#list}}
<div class="swiper-slide" style="{{styleFormat this percent=1}}">
<img src="{{image2 src q=60}}">
<a class="anchor" href="{{#if link}}{{link}}{{else}}javascript:void(0);{{/if}}" fp="{{getAnalysis ../../this @index}}"></a>
</div>
{{/list}}
</div>
{{#isEqualOr type 'marquee'}}
<div class="swiper-pagination"></div>
{{/isEqualOr}}
</div>
{{/isEqualOr}}
{{#isEqualOr type 'marquee' 'swiper'}}
{{! 轮播/滑动}}
<div class="swiper-container {{type}}" data-loop="{{loop}}" {{#if spaceBetween}}data-spacebetween="{{spaceBetween}}"{{/if}} {{#if autoplay}}data-autoplay="{{autoplay}}"{{/if}}>
<div class="swiper-wrapper">
{{#list}}
<div class="swiper-slide" style="{{styleFormat this percent=1}}">
<img src="{{image2 src q=60}}">
<a class="anchor" href="{{#if link}}{{link}}{{else}}javascript:void(0);{{/if}}" fp="{{getAnalysis ../../this @index}}"></a>
</div>
{{/list}}
</div>
{{#isEqualOr type 'marquee'}}
<div class="swiper-pagination"></div>
{{/isEqualOr}}
</div>
{{/isEqualOr}}
{{#isEqualOr type 'tab'}}
{{! tab}}
<div class="tab-container">
{{#repeat count}}
<a class="anchor {{#if @first}}active{{/if}}" style="{{tabStyle @index ../count}}"></a>
{{/repeat}}
</div>
{{/isEqualOr}}
{{#isEqualOr type 'productGroup'}}
{{! 商品池}}
<div class="product-container item{{numOfOneRow}}" {{#if proBgImg}}style="background:url({{image2 proBgImg q=60}})repeat;"{{/if}}>
<div class="product-source" {{#unless defaultPros.length}} {{#if searchCondition }}cloneitem="{{searchCondition.limit}}"{{/if}}{{/unless}} condition='{{stringify searchCondition}}' fp="{{getAnalysis ../this @index}}">
<input class="imgwh" type="hidden" value="193x257">
{{#if defaultPros.length}}
{{#defaultPros}}
<div class="feature-product-info {{#if ../condition}}novisible{{/if}}">
<a class="first-part product-detail" href='{{producturl}}'>
<div class="product-detail-imgbox">
{{#if ../lefTopImg}}<img class="leftopimg" src="{{image2 ../lefTopImg q=60}}">{{/if}}
{{#if ../rigTopImg}}<img class="rigtopimg" src="{{image2 ../rigTopImg q=60}}">{{/if}}
<img class="product-detail-img" src="{{image2 productimg q=60}}">
</div>
{{#isEqualOr ../showPrdName '1'}}<p class="product-name">{{productname}}</p>{{/isEqualOr}}
<div class="product-detail-text">
<div class="price">
<span class="sale-price"{{#if ../fontColor}}style="color:{{../fontColor}};"{{/if}}>¥{{saleprice}}</span>
{{#if marketprice}}<span class="market-price">¥{{marketprice}}</span>{{/if}}
</div>
</div>
</a>
{{#if ../brandImg}}
<a class="second-part {{#isEqualOr ../showBrandUrl '1'}}product-brand{{else}}product-detail{{/isEqualOr}}" href='{{brandurl}}'>
<div class="brand-div">
<span class="brand-name"{{#if ../fontColor}}style="color:{{../fontColor}};"{{/if}}>{{brandname}}</span>
</div>
<img class="brand-img" src="{{image2 ../brandImg q=60}}">
</a>
{{/if}}
</div>
{{/defaultPros}}
{{else}}
<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=60}}">{{/if}}
{{#if rigTopImg}}<img class="rigtopimg" src="{{image2 rigTopImg q=60}}">{{/if}}
<img class="product-detail-img" src="">
</div>
{{#isEqualOr showPrdName '1'}}<p class="product-name"></p>{{/isEqualOr}}
<div class="product-detail-text">
<div class="price">
<span class="sale-price"{{#if fontColor}}style="color:{{fontColor}};"{{/if}}></span>
<span class="market-price"></span>
</div>
</div>
</a>
{{#if brandImg}}
<a class="second-part {{#isEqualOr showBrandUrl '1'}}product-brand{{else}}product-detail{{/isEqualOr}}" href=''>
<div class="brand-div">
<span class="brand-name" {{#if fontColor}}style="color:{{fontColor}};"{{/if}}></span>
</div>
<img class="brand-img" src="{{image2 brandImg q=60}}">
</a>
{{/if}}
</div>
{{/if}}
</div>
</div>
{{/isEqualOr}}
{{/component}}
</div>
{{/isEqualOr}}
{{/content.floors}}
{{#isEqualOr type 'tab'}}
{{! tab}}
<div class="tab-container">
{{#repeat count}}
<a class="anchor {{#if @first}}active{{/if}}" tab={{tabName @index ../tabnames}} style="{{tabStyle @index ../count}}"></a>
{{/repeat}}
</div>
{{/isEqualOr}}
{{#isEqualOr type 'productGroup'}}
{{! 商品池}}
<div class="product-container item{{numOfOneRow}}" {{#if proBgImg}}style="background:url({{image2 proBgImg q=60}})repeat;"{{/if}}>
<div class="product-source" condition='{{stringify searchCondition}}' fp="{{getAnalysis ../this @index}}"
{{#unless defaultPros.length}}
{{#if searchCondition.item}}
cloneitem="{{searchCondition.item}}"
{{else}}
cloneitem="{{searchCondition.limit}}"
{{/if}}
{{/unless}}>
<input class="imgwh" type="hidden" value="193x257">
{{#if defaultPros.length}}
{{#defaultPros}}
<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=60}}">{{/if}}
{{#if ../rigTopImg}}<img class="rigtopimg lazy" data-original="{{image2 ../rigTopImg q=60}}">{{/if}}
<img class="product-detail-img lazy" data-original="{{image2 productimg q=60}}">
</div>
{{#isEqualOr ../showPrdName '1'}}<p class="product-name">{{productname}}</p>{{/isEqualOr}}
<div class="product-detail-text">
{{#isEqualOr ../showSalePrice '1'}}
<div class="price" style="{{#if ../salePriceBgColor}}background:{{../salePriceBgColor}};{{/if}}">
<span class="sale-price"{{#if ../fontColor}}style="color:{{../fontColor}};"{{/if}}>¥{{saleprice}}</span>
{{#if marketprice}}<span class="market-price">¥{{marketprice}}</span>{{/if}}
</div>
{{/isEqualOr}}
{{#isEqualOr ../showVipPrice '1'}}
<div class="vipprice"style="{{#if ../vipFontColor}}color:{{../vipFontColor}};{{/if}}{{#if ../vipBgColor}}background:{{../vipBgColor}};{{/if}}">
<span class="vip-price-text">VIP价</span>
<span class="vip-price-val">¥{{vipprice}}</span>
</div>
{{/isEqualOr}}
</div>
</a>
{{#if ../brandImg}}
<a class="second-part {{#isEqualOr ../showBrandUrl '1'}}product-brand{{else}}product-detail{{/isEqualOr}}" href='{{brandurl}}'>
<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=60}}">
</a>
{{/if}}
</div>
{{/defaultPros}}
{{else}}
<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=60}}">{{/if}}
{{#if rigTopImg}}<img class="rigtopimg" src="{{image2 rigTopImg q=60}}">{{/if}}
<img class="product-detail-img" src="">
</div>
{{#isEqualOr showPrdName '1'}}<p class="product-name"></p>{{/isEqualOr}}
<div class="product-detail-text">
{{#isEqualOr showSalePrice '1'}}
<div class="price" style="{{#if salePriceBgColor}}background:{{salePriceBgColor}};{{/if}}">
<span class="sale-price"{{#if fontColor}}style="color:{{fontColor}};"{{/if}}></span>
<span class="market-price"></span>
</div>
{{/isEqualOr}}
{{#isEqualOr showVipPrice '1'}}
<div class="vipprice" style="{{#if vipFontColor}}color:{{vipFontColor}};{{/if}}{{#if vipBgColor}}background:{{vipBgColor}};{{/if}}">
<span class="vip-price-text">VIP价</span><span class="vip-price-val"></span>
</div>
{{/isEqualOr}}
</div>
</a>
{{#if brandImg}}
<a class="second-part {{#isEqualOr showBrandUrl '1'}}product-brand{{else}}product-detail{{/isEqualOr}}" href=''>
<div class="brand-div">
<span class="brand-name" {{#if fontColor}}style="color:{{fontColor}};"{{/if}}></span>
</div>
<img class="brand-img" src="{{image2 brandImg q=60}}">
</a>
{{/if}}
</div>
{{/if}}
</div>
</div>
{{/isEqualOr}}
{{/component}}
</div>
{{/isEqualOr}}
{{/content.floors}}
{{/unless}}
</div>
\ No newline at end of file
... ...
{{#if content.thumbnail}}
<img class="sidebar-img" src="{{image2 content.thumbnail q=60}}">
{{/if}}
<div class="sidebar">
<div class="sidebar-content">
{{#content.floors}}
{{#isEqualOr type '' 'common_floor'}}
<div class="sidebar-item">
{{#if param.bgimg}}<img src="{{image2 param.bgimg q=60}}">{{/if}}
{{#component}}
{{#isEqualOr type 'link'}}
{{#isEqualOr url 'closesidebar'}}
<a class="anchor closesidebar" style="{{styleFormat this percent=1}}" href="javascript:void(0);"></a>
{{else}}
<a class="anchor" style="{{styleFormat this percent=1}}" href="{{#if url}}{{url}}{{else}}javascript:void(0);{{/if}}"></a>
{{/isEqualOr}}
{{/isEqualOr}}
{{/component}}
</div>
{{/isEqualOr}}
{{/content.floors}}
</div>
</div>
\ No newline at end of file
... ...
... ... @@ -182,7 +182,6 @@ exports.orderSub = (req, res, next) => {
let yohoCoin = req.body.yohoCoin || 0;
let skuList = req.body.skuList || '';
let orderInfo;
let isWechat = req.yoho.isWechat;
try {
orderInfo = JSON.parse(req.cookies['order-info']);
... ... @@ -254,7 +253,15 @@ exports.orderSub = (req, res, next) => {
return co(function* () {
let result;
let ip = req.ip || '';
// 接口需要的其他参数
let otherParams = {
unionKey: unionKey, // 友盟数据
userAgent: userAgent,
isWechat: req.yoho.isWechat,
ip: req.ip || '',
udid: req.cookies._yasvd || 'yoho'
};
/* tar modified 161206 套餐 */
if (req.body.cartType === 'bundle') {
... ... @@ -262,11 +269,11 @@ exports.orderSub = (req, res, next) => {
result = yield cartModel.orderSub(uid, addressId, 'bundle', deliveryTimeId,
deliveryId, invoices, paymentTypeId, paymentType, msg, couponCode,
yohoCoin, null, unionKey, userAgent, times, activityInfo, ip, isWechat);
yohoCoin, null, times, activityInfo, otherParams);
} else {
result = yield cartModel.orderSub(uid, addressId, cartType, deliveryTimeId,
deliveryId, invoices, paymentTypeId, paymentType, msg, couponCode,
yohoCoin, skuList, unionKey, userAgent, null, null, ip, isWechat);
yohoCoin, skuList, null, null, otherParams);
}
// 提交成功清除Cookie
... ...
... ... @@ -180,23 +180,21 @@ exports.ticketsOrderCompute = (uid, productSku, buyNumber, yohoCoin) => {
* @param string $couponCode 优惠券码
* @param mixed $yohoCoin 使用的有货币数量或为空
* @param string $skuList 购买限购商品时需要传递的参数
* @param string $qhyUnio 友盟有关信息
* @param string|null $userAgent 联盟过来用户下单时需要的User-Agent信息
* @param int $times
* @param null $activityInfo 套餐数据
* @param isWechat 是否是微信商城
* @param otherParams 其他参数
* @return array 接口返回的数据
*/
exports.orderSub = (uid, addressId, cartType, deliveryTime,
deliveryWay, invoices, paymentId, paymentType, remark,
couponCode, yohoCoin, skuList, qhyUnio,
userAgent, times, activityInfo, ip, isWechat) => {
if (!qhyUnio) {
qhyUnio = '';
couponCode, yohoCoin, skuList, times, activityInfo, otherParams) => {
if (!otherParams.unionKey) {
otherParams.unionKey = '';
}
if (!userAgent) {
userAgent = null;
if (!otherParams.userAgent) {
otherParams.userAgent = null;
}
if (!times) {
... ... @@ -221,8 +219,7 @@ exports.orderSub = (uid, addressId, cartType, deliveryTime,
return shoppingAPI.orderSub(uid, addressId, cartType, deliveryTime,
deliveryWay, invoices, paymentId, paymentType,
remark, couponCode, yohoCoin, skuList, qhyUnio,
userAgent, times, activityInfo, ip, isWechat).then(orderSubRes => {
remark, couponCode, yohoCoin, skuList, times, activityInfo, otherParams).then(orderSubRes => {
let finalResult = {};
if (orderSubRes && orderSubRes.data && orderSubRes.data.is_hint === 'Y') {
... ...
... ... @@ -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) : {};
});
};
... ...
... ... @@ -149,16 +149,15 @@ exports.checkTickets = (uid, productSku, buyNumber, useYohoCoin, yohoCoinMode) =
* @param string $couponCode 优惠券码
* @param mixed $yohoCoin 使用的有货币数量或为空
* @param string $skuList 购买限购商品时需要传递的参数
* @param string $qhyUnion 友盟有关信息
* @param string|null $userAgent 联盟过来用户下单时需要的User-Agent信息
* @param $times
* @param null $activityInfo 套餐信息
* @param isWechat 是否是微信商城
* @param @param otherParams 其他参数
* @return array 接口返回的数据
*/
exports.orderSub = (uid, addressId, cartType, deliveryTime,
deliveryWay, invoices, paymentId, paymentType, remark, couponCode,
yohoCoin, skuList, qhyUnion, userAgent, times, activityInfo, ip, isWechat) => {
yohoCoin, skuList, times, activityInfo, otherParams) => {
if (!activityInfo) {
activityInfo = null;
}
... ... @@ -173,7 +172,8 @@ exports.orderSub = (uid, addressId, cartType, deliveryTime,
payment_id: paymentId,
payment_type: paymentType,
remark: remark,
uid: uid
uid: uid,
udid: otherParams.udid
};
/* tar add 161130 结算优化 */
... ... @@ -223,19 +223,19 @@ exports.orderSub = (uid, addressId, cartType, deliveryTime,
}
// 友盟有关信息的传递
if (qhyUnion) {
params.qhy_union = qhyUnion;
if (otherParams.unionKey) {
params.qhy_union = otherParams.unionKey;
}
// 是否是微信商城
if (isWechat) {
if (otherParams.isWechat) {
params.client_type = 'wechat';
}
return api.post('', params, {
headers: {
'X-Forwarded-For': ip || '',
'User-Agent': userAgent
'X-Forwarded-For': otherParams.ip || '',
'User-Agent': otherParams.userAgent
}
});
};
... ...
... ... @@ -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]) {
... ...
... ... @@ -188,6 +188,7 @@ const addressModify = (req, res, next) => {
*/
const changeAddress = (req, res, next) => {
let uid = req.user.uid;
let udid = req.cookies._yasvd || 'yoho';
if (!uid) {
return res.json({
... ... @@ -202,7 +203,8 @@ const changeAddress = (req, res, next) => {
username: req.body.username,
areaCode: req.body.area_code,
address: req.body.address,
mobile: req.body.mobile
mobile: req.body.mobile,
udid: udid
}).then(result => {
res.json(result);
}).catch(next);
... ...
... ... @@ -374,7 +374,8 @@ const changeAddress = (params) => {
user_name: params.username,
area_code: params.areaCode,
address: params.address,
mobile: params.mobile
mobile: params.mobile,
udid: params.udid
};
if (params.addressId) {
... ...
... ... @@ -90,8 +90,8 @@ router.get('/helpDetail', help.helpDetail);
// 意见反馈
router.get('/suggest', suggest.suggestData);
router.post('/upAndDown', suggest.upAndDown);
router.get('/suggestSub', suggest.suggestSub);
router.post('/savesuggest', suggest.saveSuggest);
router.get('/suggestSub', auth, suggest.suggestSub);
router.post('/savesuggest', auth, suggest.saveSuggest);
// 消息
router.use('/message', auth, disableBFCache, message.index);
... ...
... ... @@ -532,35 +532,32 @@
</p>
<p>
第二十三条 如借款发生逾期,则自逾期之日起您应按照日息万分之二点五的逾期利率向信而富支付逾期利息,同时您还需要根据如下标准按日向信而富支付延迟还款服务费:如借款金额为500元以内(含500元),则延迟还款服务费为1元/天;如借款金额为501—1000元(含1000元),则延迟还款服务费为2元/天;如借款金额为1001—1500元(含1500元),则延迟还款服务费为3元/天; 如借款金额为1501-2000元(含2000元),则延迟还款服务费为4元/天,以此类推,借款金额每增加500元,逾期费用增加1元/天。逾期3天免收延迟还款服务费,逾期超过3天,按实际逾期总天数收取延迟还款服务费,逾期超过90天以上,将不再计收延迟还款服务费。利息、逾期利息和延迟还款服务费应计算至实际清偿日止,具体数值以信而富平台借款订单详情为准,有特别说明的除外。
</p>
<p>
第二十四条 <span class='bold underline'>您每次归还及支付的款项,将按延迟还款服务费、利息、本金的顺序依次进行清偿,具体扣除金额以订单详情为准。</span>信而富有权依据法律、法规或监管要求单方变更上述还款顺序。
第二十三条 您每次归还及支付的款项,将按利息、延迟还款服务费、本金的顺序依次进行清偿,具体扣除金额以订单详情为准。信而富有权依据法律、法规或监管要求单方变更上述还款顺序。
</p>
</div>
<div class='help-group'>
<h2>第五章违约责任和催收管理</h2>
<p>
第二十条 如您未能在到期还款日前还清欠款,信而富有权直接或通过<span class='bold'>Yoho!Buy有货</span>向您作出逾期催款提示,催款手段包含但不限于短信、电话、微信、信而富平台系统通知、<span class='bold'>Yoho!Buy有货</span>平台通知等。
第二十条 如您未能在到期还款日前还清欠款,信而富有权直接或通过<span class='bold'>Yoho!Buy有货</span>向您作出逾期催款提示,催款手段包含但不限于短信、电话、微信、信而富平台系统通知、<span class='bold'>Yoho!Buy有货</span>平台通知等。
</p>
<p>
第二十<span class='bold underline'>信而富有权对逾期用户的违约行为采取以下措施:1、收取延迟还款服务费;2、向征信数据机构报告发送与用户还款违约行为相关的信息。3、将用户列入黑名单并拒绝再次提供借款服务。</span>
第二十<span class='bold underline'>信而富有权对逾期用户的违约行为采取以下措施:1、收取延迟还款服务费;2、向征信数据机构报告发送与用户还款违约行为相关的信息。3、将用户列入黑名单并拒绝再次提供借款服务。</span>
</p>
<p>
第二十条 信而富有权通过即时通讯工具、短信、电话、信函、上门等形式向逾期用户进行还款提示或催收,该等情形下进行的还款提示及催收不视为对用户权利的侵犯。
第二十条 信而富有权通过即时通讯工具、短信、电话、信函、上门等形式向逾期用户进行还款提示或催收,该等情形下进行的还款提示及催收不视为对用户权利的侵犯。
</p>
<p>
第二十<span class='bold underline'>信而富将依据您的还款记录决定您是否可继续再次借款。如您逾期还款超过180天的,或您以明示或默示的方式许可他人代为借款的,信而富有权选择单方面终止本协议,且有权采取有效债权保全措施处置您拥有的资产。协议终止并不影响信而富、相关方和您之间已经发生的债权债务关系及其相关权利义务,您仍须依约偿还剩余欠款和相应借款费用,并承担信而富和相关方实现债权的费用(包括但不限于律师费、诉讼费、评估费、拍卖费等)。</span>
第二十<span class='bold underline'>信而富将依据您的还款记录决定您是否可继续再次借款。如您逾期还款超过180天的,或您以明示或默示的方式许可他人代为借款的,信而富有权选择单方面终止本协议,且有权采取有效债权保全措施处置您拥有的资产。协议终止并不影响信而富、相关方和您之间已经发生的债权债务关系及其相关权利义务,您仍须依约偿还剩余欠款和相应借款费用,并承担信而富和相关方实现债权的费用(包括但不限于律师费、诉讼费、评估费、拍卖费等)。</span>
</p>
<p>
第二十九条信而富有权在您预授信额度有效期内对您的资信状况开展实时授信审核,包括但不限于通过征信数据机构定期查询及更新您的个人信用报告、向有关机构、单位和个人了解您的财产及资信状况等。
第二十八条 信而富有权在您预授信额度有效期内对您的资信状况开展实时授信审核,包括但不限于通过征信数据机构定期查询及更新您的个人信用报告、向有关机构、单位和个人了解您的财产及资信状况等。
</p>
<p>
三十条根据实时授信审核结果,信而富有权依据其认定的用户资信状况或收入状况决定是否降低或停用用户的预授信额度,或采取包括但不限于提前解除本协议、拒绝用户进行借款等相关措施。在本协议生效后至借款发放前,信而富亦有权根据实时授信审核结果决定是否最终发放借款。
二十九条 根据实时授信审核结果,信而富有权依据其认定的用户资信状况或收入状况决定是否降低或停用用户的预授信额度,或采取包括但不限于提前解除本协议、拒绝用户进行借款等相关措施。在本协议生效后至借款发放前,信而富亦有权根据实时授信审核结果决定是否最终发放借款。
</p>
<p>
第三十一条如借款人发生死亡或丧失民事行为能力等情形的,应由借款人的遗产继承人、受遗赠人、法定代理人或监护人等依法清偿借款人应当承担的全部债务,包括本金、借款费用等。
第三十如借款人发生死亡或丧失民事行为能力等情形的,应由借款人的遗产继承人、受遗赠人、法定代理人或监护人等依法清偿借款人应当承担的全部债务,包括本金、借款费用等。
</p>
</div>
... ... @@ -568,28 +565,28 @@
<div class='help-group'>
<h2>第六章 附则</h2>
<p>
第三十条 本协议适用中华人民共和国大陆地区法律,若因本协议的成立、生效、履行、解释等发生纠纷,由各方协商处理;如果协商不成,任何一方可依法向上海市长宁区人民法院提起诉讼,以诉讼方式解决争议。在争议解决期间,若该争议不影响本协议其他条款的履行,则其他条款应继续履行。
第三十条 本协议适用中华人民共和国大陆地区法律,若因本协议的成立、生效、履行、解释等发生纠纷,由各方协商处理;如果协商不成,任何一方可依法向上海市长宁区人民法院提起诉讼,以诉讼方式解决争议。在争议解决期间,若该争议不影响本协议其他条款的履行,则其他条款应继续履行。
</p>
<p>
第三十条 信而富以您在借款操作过程中登记的通讯方式(包括但不限于地址、电邮、传真、手机等)向您发送相关信息;如您通讯方式发生变更时,应及时通知信而富;您未通知的,信而富按您在信而富处或<span class='bold'>Yoho!Buy有货</span>记载的最新通讯方式发送或接受的相关信息,均视为已送达给您本人或是用户本人发起。
第三十条 信而富以您在借款操作过程中登记的通讯方式(包括但不限于地址、电邮、传真、手机等)向您发送相关信息;如您通讯方式发生变更时,应及时通知信而富;您未通知的,信而富按您在信而富处或<span class='bold'>Yoho!Buy有货</span>记载的最新通讯方式发送或接受的相关信息,均视为已送达给您本人或是用户本人发起。
</p>
<p>
第三十<span class='bold underline'>您确认借款、还款过程中所涉及的记录数据、金额数据等均以信而富系统平台记录的数据为准。</span>
第三十<span class='bold underline'>您确认借款、还款过程中所涉及的记录数据、金额数据等均以信而富系统平台记录的数据为准。</span>
</p>
<p>
第三十<span class='bold underline'>您同意信而富或相关方可以将与您借款对应的债权的部分或全部转让给第三方,该等债权转让事宜无需事先通知您,亦不影响您的还款义务及还款方式,在债权转让后,您仍应按照本协议约定向信而富或信而富指示的第三方归还、支付本金及借款费用。</span>
第三十<span class='bold underline'>您同意信而富或相关方可以将与您借款对应的债权的部分或全部转让给第三方,该等债权转让事宜无需事先通知您,亦不影响您的还款义务及还款方式,在债权转让后,您仍应按照本协议约定向信而富或信而富指示的第三方归还、支付本金及借款费用。</span>
</p>
<p>
第三十条 您确认,在“信而富现金贷”业务中,信而富负责提供或寻找或管理出借资金、审核用户资质、提供资信评估、决定是否授信及授信额度、进行逾期催收等与借款业务相关的事宜并收取相关费用;并授权第三方支付平台将资金扣划至指定账户。就前述信而富所执行的各项事宜,您予以全权授权且不持任何异议。信而富亦有权授权其旗下的任一公司履行本协议的服务事项,或委托合作的第三方予以执行。 <span class='bold underline'>在任何情形下,信而富在本协议项下所提供的服务均不能被理解为对用户的借款提供了任何形式的担保或保证,本协议项下用户的借款所涉的全部法律责任由用户本人承担,信而富不予承担任何形式的责任。</span>
第三十条 您确认,在“信而富现金贷”业务中,信而富负责提供或寻找或管理出借资金、审核用户资质、提供资信评估、决定是否授信及授信额度、进行逾期催收等与借款业务相关的事宜并收取相关费用;并授权第三方支付平台将资金扣划至指定账户。就前述信而富所执行的各项事宜,您予以全权授权且不持任何异议。信而富亦有权授权其旗下的任一公司履行本协议的服务事项,或委托合作的第三方予以执行。 <span class='bold underline'>在任何情形下,信而富在本协议项下所提供的服务均不能被理解为对用户的借款提供了任何形式的担保或保证,本协议项下用户的借款所涉的全部法律责任由用户本人承担,信而富不予承担任何形式的责任。</span>
</p>
<p>
第三十<span class='bold underline'>您保证,您签署本协议及执行本协议各约定行为均发生在中国大陆地区,您不会在除中国大陆地区外的其他地域执行本协议项下之约定行为。</span>
第三十<span class='bold underline'>您保证,您签署本协议及执行本协议各约定行为均发生在中国大陆地区,您不会在除中国大陆地区外的其他地域执行本协议项下之约定行为。</span>
</p>
<p>
第三十<span class='bold underline'>本协议经用户在信而富平台点击“同意协议并继续“按钮且通过交易动态密码验证后立即生效。</span>
第三十<span class='bold underline'>本协议经用户在信而富平台点击“同意协议并继续“按钮且通过交易动态密码验证后立即生效。</span>
</p>
<p>
第三十<span class='bold underline'>在法律法规允许的范围内,本协议的解释权归信而富所有。</span>
第三十<span class='bold underline'>在法律法规允许的范围内,本协议的解释权归信而富所有。</span>
</p>
</div>
</div>
\ No newline at end of file
... ...
... ... @@ -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');
... ... @@ -81,7 +83,9 @@ const common = {
let passLogin = _.get(req, 'cookies._WX_PASS_LOGIN', false);
if (req.yoho.isWechat && !passLogin) {
return res.redirect('/passport/login/wechat');
return res.redirect(helpers.urlFormat('/passport/login/wechat', {
refer: req.query.refer || req.get('Referer') || '/'
}));
}
next();
},
... ... @@ -120,19 +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);
res.render('login', {
width750: true,
loginIndex: true, // 模板中使用JS的标识
captchaShow: true, // 170306 因为暴力破解密码问题,要求每次都展示验证码
captchaShow: req.yoho.captchaShow,
backUrl: 'javascript:history.go(-1)', // eslint-disable-line
showHeaderImg: true, // 控制显示头部图片
isPassportPage: true, // 模板中模块标识
... ... @@ -162,21 +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);
res.render('international', {
width750: true,
backUrl: 'javascript:history.go(-1)', // eslint-disable-line
loginInternational: true, // 模板中使用JS的标识
captchaShow: true, // 170306 因为暴力破解密码问题,要求每次都展示验证码
captchaShow: req.yoho.captchaShow,
isPassportPage: true, // 模板中模块标识
headerText: '登录',
areaCode: '+86', // 默认区号
... ... @@ -206,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;
... ... @@ -250,6 +237,18 @@ const local = {
const wechat = {
login: (req, res, next) => {
// 微信里边已经登录的时候,不再跳转登录
if (req.user.uid) {
let refer = req.query.refer || decodeURI(req.cookies.refer) || config.siteUrl;
if (/sign|login/.test(refer)) {
refer = `${config.siteUrl}/home`;
}
refer = utils.refererLimit(refer);
return res.redirect(refer);
}
// 设置为原链接标识originalUrl
req.session.originalUrl = 'true';
req.session.authState = uuid.v4();
... ... @@ -389,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,15 +23,44 @@ const check = (req, res, next) => {
return next();
}
// 使用极验证
let useGeetest = !_.get(req.app.locals.wap, 'geetest.validation', false);
// 默认取配置总开关来决定是否展示验证码
req.yoho.captchaShow = !_.get(req.app.locals.wap, 'close.loginValidation', false);
// 某次请求极验证调用注册失败,强制使用自有图形验证码
if (req.session.useYohoCaptcha) {
useGeetest = false;
}
co(function* () {
// 如果是账号密码登录,那么需要检查是否登录失败过,登录失败过展示验证码
if (req.path === '/passport/login/auth') {
let hasErrorLog = yield cache.get(`loginErrorIp:${req.yoho.clientIp}`);
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);
});
};
/**
... ...
... ... @@ -2,6 +2,7 @@
const _ = require('lodash');
const aes = require('./aes-pwd');
const authcode = require('../../../utils/authcode');
const logger = global.yoho.logger;
const sign = global.yoho.sign;
const api = global.yoho.API;
const uuid = require('uuid');
... ... @@ -35,10 +36,13 @@ class Auth {
param.shopping_key = shoppingKey;
}
logger.info(`${profile}, login from ${ip}`);
return api.post('', param, {
headers: {
'user-agent': 'yoho/nodejs',
'X-YOHO-IP': ip
'X-YOHO-IP': ip,
'X-Forwarded-For': ip
}
});
}
... ...
... ... @@ -27,7 +27,7 @@ const router = express.Router(); // eslint-disable-line
router.get('/passport/geetest/register', geetest.register);
// 兼容老的路由
router.get('/signin.html', validateCode.load, login.common.weixinCheck,
router.get('/signin.html', login.common.weixinCheck, validateCode.load,
login.common.beforeLogin, login.common.clearCookie, smsLogin.loginPage);
router.get('/reg.html', validateCode.load, disableBFCahce, reg.index);
router.get('/login.html', validateCode.load,
... ... @@ -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);
... ... @@ -78,10 +89,6 @@ router.get('/passport/login/qq/callback', login.qq.callback);
router.get('/passport/login/alipay', login.common.beforeLogin, login.alipay.login);
router.get('/passport/login/alipay/callback', login.alipay.callback);
// alipay登录
router.get('/login/alipay', login.common.beforeLogin, login.alipay.login);
router.get('/login/alipay/callback', login.alipay.callback);
// 登录绑定
router.get('/passport/bind/index', validateCode.load, bind.indexPage);
router.post('/passport/bind/bindCheck', validateCode.check, bind.bindCheck);
... ...
... ... @@ -10,7 +10,7 @@
<input id="pwd" class="pwd input" type="password" placeholder="密码">
</div>
{{!--图片验证--}}
<div data-geetest="{{useGeetest}}" id="js-img-check"></div>
<div data-userverify="{{captchaShow}}" data-geetest="{{useGeetest}}" id="js-img-check"></div>
<span id="btn-login" class="btn btn-login disble row">登录</span>
</div>
... ...
... ... @@ -9,7 +9,7 @@
<input id="pwd" class="pwd input" type="password" placeholder="密码">
</div>
{{!--图片验证--}}
<div data-geetest="{{useGeetest}}" id="js-img-check"></div>
<div data-userverify="{{captchaShow}}" data-geetest="{{useGeetest}}" id="js-img-check"></div>
<span id="btn-login" class="btn btn-login disable">登录</span>
<p class="op-container">
<a class="op-item internat" href={{internationalUrl}}>海外手机</a>
... ...
... ... @@ -231,6 +231,7 @@ const category = (req, res, next) => {
order: '0',
page: 1,
limit: 12,
isApp: params.app_version
}, params);
if (uid) {
... ...
... ... @@ -256,7 +256,7 @@ const shop = {
module: 'product',
page: 'shop.base',
pageHeader: headerModel.setNav({
navTitle: baseShop.shopName
navTitle: shopInfo.shop_name
}),
goodList: baseShop,
showDownloadApp: true,
... ...
... ... @@ -123,6 +123,8 @@ const selectHotrank = (yhChannel, gender, sort, tabId, limit, page, notab) => {
}
return formData;
} else {
return {};
}
});
... ...
... ... @@ -36,7 +36,7 @@ const domains = {
module.exports = {
app: 'h5',
appVersion: '5.5.1', // 调用api的版本
appVersion: '5.5.2', // 调用api的版本
port: 6001,
siteUrl: '//m.yohobuy.com',
assetUrl: '//127.0.0.1:5001',
... ... @@ -78,11 +78,6 @@ module.exports = {
handleExceptions: true,
maxFiles: 7
},
udp: { // send by udp
measurement: 'yohobuy_wap_node_log',
level: 'error', // logger level
port: '4444' // influxdb port
},
console: {
level: 'info',
colorize: 'all',
... ...
... ... @@ -8,9 +8,9 @@ const qpsLimiter = require('./rules/qps-limit');
const captchaPolicy = require('./policies/captcha');
const IP_WHITE_LIST = [
// '106.38.38.146',
// '218.94.75.58'
'106.38.38.146',
'218.94.75.58',
'218.94.75.50'
];
const limiter = (rule, policy, context) => {
... ... @@ -18,14 +18,18 @@ const limiter = (rule, policy, context) => {
};
module.exports = (req, res, next) => {
let remoteIp = req.get('X-Forwarded-For') || req.connection.remoteAddress;
logger.debug('request remote ip: ', remoteIp);
let remoteIp = req.get('X-Forwarded-For') || req.get('X-Real-IP') || '';
if (remoteIp.indexOf(',') > 0) {
let arr = remoteIp.split(',');
remoteIp = arr[0];
remoteIp = arr[arr.length - 1];
}
remoteIp = _.trim(remoteIp);
if (_.startsWith(remoteIp, '10.66.')) {
remoteIp = req.get('X-Real-IP');
}
const excluded = _.includes(IP_WHITE_LIST, remoteIp);
... ...
... ... @@ -22,6 +22,10 @@ module.exports = (req, res, next) => {
return next();
}
if (_.toNumber(res.statusCode) === 403) {
return res.end();
}
if (req.xhr) {
return res.json({
code: 400,
... ...
... ... @@ -21,7 +21,11 @@ const _getClientIp = req => {
remoteIp = _.trim(arr[arr.length - 1]);
}
return remoteIp;
if (_.startsWith(remoteIp, '10.66.')) {
remoteIp = req.get('X-Real-IP');
}
return _.trim(remoteIp);
};
module.exports = () => {
... ...
... ... @@ -101,7 +101,7 @@
<script type="text/javascript" src="{{src}}"></script>
{{/loadJs}}
{{#isFeature}}
<script type="text/javascript" src="//cdn.yoho.cn/js-sdk/1.2.0/jssdk.js"></script>
<script type="text/javascript" src="//cdn.yoho.cn/js-sdk/1.2.2/jssdk.js"></script>
{{/isFeature}}
{{#unless devEnv}}
{{> analysis}}
... ...
... ... @@ -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.3.7/yas.js', '_yas'));
}(window, document, 'script', (document.location.protocol === 'https:' ? 'https:' : 'http:') + '//cdn.yoho.cn/yas-jssdk/2.3.8/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.3.7', 'yohobuy_m', uid, '', '');
window._yas(1 * new Date(), '2.3.8', 'yohobuy_m', uid, '', '');
}
setTimeout(function() {
... ...
{
"name": "m-yohobuy-node",
"version": "5.5.5",
"version": "5.5.20",
"private": true,
"description": "A New Yohobuy Project With Express",
"repository": {
... ... @@ -50,13 +50,14 @@
"xml2js": "^0.4.17",
"yoho-express-session": "^2.0.0",
"yoho-md5": "^2.0.0",
"yoho-node-lib": "=0.2.11",
"yoho-node-lib": "=0.2.17",
"yoho-zookeeper": "^1.0.8"
},
"devDependencies": {
"autoprefixer": "^6.7.4",
"babel-core": "^6.24.0",
"babel-loader": "^6.4.1",
"babel-polyfill": "^6.23.0",
"babel-preset-env": "^1.2.2",
"css-loader": "^0.27.3",
"cssnano": "^3.10.0",
... ...
... ... @@ -66,7 +66,7 @@ const cssLoader = (env, type) => {
const getEntries = () => {
const entries = {
libs: ['yoho-jquery'],
libs: ['babel-polyfill', 'yoho-jquery'],
index: path.join(__dirname, '../scss/index.css'),
common: path.join(__dirname, '../scss/common.css'),
feature: path.join(__dirname, '../scss/feature.css')
... ...
let $ = require('yoho-jquery');
let Swiper = require('yoho-swiper');
var $ = require('yoho-jquery');
var lazyLoad = require('yoho-jquery-lazyload');
var Swiper = require('yoho-swiper');
var yoho = require('../yoho-app');
global.jQuery = $;
let isAndroid = /(Android)/i.test(navigator.userAgent);
let isWechat = /micromessenger/i.test(navigator.userAgent);
lazyLoad($('img.lazy'));
function swiperInit() {
$('.swiper-container').each(function() {
let opt = {
... ... @@ -52,19 +56,27 @@ function topNavInit() {
}
function ceXuanFuInit() {
$('#load_cxf').load('http://feature.yoho.cn/public/cexuanfu/cexuanfu.html', function() {
$('#cxf').click(function() {
if ($(this).hasClass('isclick')) {
$('.cxfall').hide();
$(this).removeClass('iscxf');
} else {
$('.cxfall').show();
$(this).addClass('iscxf');
var cxf = $('#sidebar');
var pageid = cxf.attr('pageid');
if (!pageid) {
return;
}
$('#sidebar').load('//activity.yoho.cn/featuresidebar/' + pageid + '.html', function() {
$('.sidebar-img').click(function() {
$('.sidebar').show();
});
$('.sidebar').click(function(e) {
var $cur = $(e.target);
if (!$cur.closest('.sidebar-content').length) {
$(this).hide();
}
});
$('.cxfallbg').click(function() {
$(this).parent().hide();
$('#cxf').removeClass('iscxf');
$('.closesidebar').click(function() {
$('.sidebar').hide();
});
});
}
... ... @@ -99,31 +111,65 @@ function videoInit() {
}
function tabInit() {
let tabContainer = $('.tab-container');
let nextDom = tabContainer.parent().nextAll();
let tab = tabContainer.find('a.anchor');
$('.tab-container').each(function() {
var tab = $(this).find('a.anchor');
var tabname = (tab.attr('tab') || '').split('_')[0] + '_';
tab.on('click', function() {
tab.removeClass('active');
$(this).addClass('active');
let index = $(this).index() + 1;
for (let i = 1; i <= tab.length; i++) {
if (index === i) {
$('div[tabname="' + tabname + i + '"]').show();
} else {
$('div[tabname="' + tabname + i + '"]').hide();
}
}
});
tab.on('click', function() {
tab.removeClass('active');
$(this).addClass('active');
for (let i = 2; i <= tab.length; i++) {
$('div[tabname="' + tabname + i + '"]').hide();
}
});
}
let index = $(this).index();
function modalInit() {
$('a.modalimg').on('click', function() {
$($(this).next('.modal')[0]).show();
});
for (let i = 0; i < tab.length; i++) {
if (index === i) {
$(nextDom[i]).show();
} else {
$(nextDom[i]).hide();
}
}
$('.modal-close').on('click', function() {
$($(this).parent().get(0)).hide();
return false;
});
for (let i = 1; i < tab.length; i++) {
$(nextDom[i]).hide();
}
$('.modal').on('click', function(e) {
if (e.target.tagName === 'IMG') {
return false;
} else {
$(this).hide();
return false;
}
});
}
$(function() {
if ($('.over').length) {
// 过期/删除 状态的 活动
setTimeout(function() {
yoho.goHome();
}, 3000);
return false;
}
// tab
tabInit();
// 微信中点击之后,返回跳到指定位置
let totalH, scH;
let top = localStorage.changtu1;
... ... @@ -149,6 +195,6 @@ $(function() {
// 视频相关
videoInit();
// tab
tabInit();
// 模态框
modalInit();
});
... ...
... ... @@ -13,6 +13,7 @@ let $phoneNum = $('#phone-num'),
$loginBtn = $('#btn-login'),
$captcha = $('#js-img-check'),
useVerify = $captcha.data('userverify'), // 170406 是否使用验证
pnPass = false,
pwdPass = false;
... ... @@ -23,15 +24,18 @@ let tip = require('plugin/tip');
let trim = $.trim;
let showErrTip = tip.show;
let validate = new Validate($captcha, {
useREM: {
rootFontSize: 40,
picWidth: 150
}
});
let validate = {};
validate.init();
if (useVerify) {
validate = new Validate($captcha, {
useREM: {
rootFontSize: 40,
picWidth: 150
}
});
validate.init();
}
// 登录按钮状态切换
function switchLoginBtnStatus() {
... ... @@ -45,6 +49,47 @@ function resetForm() {
$loginBtn.text('登录').addClass('disable');
}
/**
* 登录校验
*/
function loginAuth(params) {
$.ajax({
type: 'POST',
url: '/passport/login/auth',
data: params,
success: function(data) {
let res;
validate && validate.type === 2 && validate.refresh();
if (data.code === 200) {
res = data.data;
showErrTip('登录成功');
// 3秒后强制跳转
setTimeout(() => {
location.href = res.href;
}, 1500);
$loginBtn.text('登录成功');
showErrTip('登录成功');
} else {
if (useVerify && data.captchaShow) {
((data.changeCaptcha && validate.type !== 2) && validate.refresh());
}
showErrTip(data.message);
resetForm();
}
},
error: function() {
showErrTip('网络断开连接啦~');
$loginBtn.text('登录');
validate && validate.refresh();
}
});
}
// Android-UC下显示select的direction:rtl无效的临时解决办法
api.selectCssHack($countrySelect);
... ... @@ -90,52 +135,21 @@ $loginBtn.on('touchstart', function() {
}
if ((api.phoneRegx[areaCode].test(pn) || areaCode !== '+86') && api.pwdValidate(pwd)) {
validate.getResults().then((result) => {
$loginBtn.text('正在登录...').addClass('disable');
let params = {
areaCode: areaCode.replace('+', ''),
account: pn,
password: pwd
};
$.extend(params, result);
$.ajax({
type: 'POST',
url: '/passport/login/auth',
data: params,
success: function(data) {
let res;
validate.type === 2 && validate.refresh();
if (data.code === 200) {
res = data.data;
showErrTip('登录成功');
// 3秒后强制跳转
setTimeout(() => {
location.href = res.href;
}, 1500);
$loginBtn.text('登录成功');
showErrTip('登录成功');
} else {
if (data.captchaShow) {
((data.changeCaptcha && validate.type !== 2) && validate.refresh());
}
showErrTip(data.message);
resetForm();
}
},
error: function() {
showErrTip('网络断开连接啦~');
$loginBtn.text('登录');
validate.refresh();
}
let params = {
areaCode: areaCode.replace('+', ''),
account: pn,
password: pwd
};
if (useVerify) {
validate.getResults().then((result) => {
$loginBtn.text('正在登录...').addClass('disable');
$.extend(params, result);
loginAuth(params);
});
});
} else {
loginAuth(params);
}
} else {
showErrTip('账号或密码有错误,请重新输入');
$loginBtn.text('登录').addClass('disable');
... ...
... ... @@ -32,7 +32,9 @@ let validate = new Validate($captcha, {
}
});
validate.init();
if ($captcha.data('userverify')) {
validate.init();
}
// 登录按钮状态切换
function switchLoginBtnStatus() {
... ... @@ -60,6 +62,67 @@ function hideRetrivePanel() {
$ways.hide();
}
/**
* 登录校验
*/
function loginAuth(params, acc) {
$.ajax({
type: 'POST',
url: '/passport/login/auth',
data: params,
success: function(data) {
let res,
LOGI_TYPE;
if (acc.indexOf('@') > 0) {
LOGI_TYPE = 8;
} else {
LOGI_TYPE = 5;
}
if (window._yas && window._yas.sendCustomInfo) {
window._yas.sendCustomInfo({
op: 'YB_MY_LOGIN_C',
param: JSON.stringify({
C_ID: window._ChannelVary[window.cookie('_Channel')],
LOGI_TYPE: LOGI_TYPE
})
}, true);
}
validate && validate.type === 2 && validate.refresh();
if (data.code === 200) {
res = data.data;
showErrTip('登录成功');
location.href = res.href;
$loginBtn.text('登录成功');
} else {
$captcha.data('userverify', data.captchaShow);
if (data.captchaShow) {
if (validate.atWorking) {
((data.changeCaptcha && validate.type !== 2) && validate.refresh());
} else {
validate.init();
}
}
showErrTip(data.message);
resetForm();
}
return data;
},
error: function() {
showErrTip('网络断开连接啦~');
validate && validate.refresh();
},
complete: function() {
$loginBtn.text('登录').removeClass('disable');
}
});
}
// 密码显示与隐藏
api.bindEyesEvt();
... ... @@ -95,67 +158,23 @@ $loginBtn.on('touchstart', function() {
// 验证账号(数字或者邮箱)和密码合理性
if ((/^[0-9]+$/.test(acc) || api.emailRegx.test(acc)) && api.pwdValidate(pwd)) {
validate.getResults().then((result) => {
$loginBtn.text('正在登录...').addClass('disable');
let params = {
account: acc,
password: pwd
};
$.extend(params, result);
$.ajax({
type: 'POST',
url: '/passport/login/auth',
data: params,
success: function(data) {
let res,
LOGI_TYPE;
if (acc.indexOf('@') > 0) {
LOGI_TYPE = 8;
} else {
LOGI_TYPE = 5;
}
if (window._yas && window._yas.sendCustomInfo) {
window._yas.sendCustomInfo({
op: 'YB_MY_LOGIN_C',
param: JSON.stringify({
C_ID: window._ChannelVary[window.cookie('_Channel')],
LOGI_TYPE: LOGI_TYPE
})
}, true);
}
validate.type === 2 && validate.refresh();
if (data.code === 200) {
res = data.data;
showErrTip('登录成功');
location.href = res.href;
$loginBtn.text('登录成功');
} else {
if (data.captchaShow) {
((data.changeCaptcha && validate.type !== 2) && validate.refresh());
}
showErrTip(data.message);
resetForm();
}
return data;
},
error: function() {
showErrTip('网络断开连接啦~');
validate.refresh();
},
complete: function() {
$loginBtn.text('登录').removeClass('disable');
}
});
}, () => {});
let params = {
account: acc,
password: pwd
};
if ($captcha.data('userverify')) {
validate.getResults().then((result) => {
$loginBtn.text('正在登录...').addClass('disable');
$.extend(params, result);
// auth
loginAuth(params, acc);
}, () => {});
} else {
loginAuth(params, acc);
}
} else {
showErrTip('账号或密码有错误,请重新输入');
$loginBtn.text('登录').removeClass('disable');
... ...
... ... @@ -102,12 +102,11 @@ yoho = {
i;
url = (url || '').split('?');
hashs = url[1].split('&');
hashs = (url[1] || '').split('&');
if (hashs && hashs.length) {
for (i = 0; i < hashs.length; i++) {
hash = hashs[i].split('=');
console.log(hashs[i]);
query[hash[0]] = hash[1];
}
}
... ... @@ -174,6 +173,19 @@ yoho = {
$appLink.attr('href', url);
$appLink[0].click();
return false;
},
goHome: function() {
var url = '//m.yohobuy.com/';
if (yoho.isApp) {
url = url + '?openby:yohobuy=' + JSON.stringify({
action: 'go.home'
});
}
$appLink.attr('href', url);
$appLink[0].click();
return false;
}
};
... ...
... ... @@ -150,3 +150,157 @@ body {
height: 100%;
}
}
.video {
position: fixed;
top: -100%;
width: 100%;
height: 360px;
z-index: 3;
&.android {
top: 30%;
z-index: 1002;
}
}
.video-android-bg {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
z-index: 1001;
background: #000;
opacity: 0.7;
}
.video-android-close {
position: fixed;
top: 26.2%;
right: 10px;
width: 35px;
height: 35px;
z-index: 1003;
background-image: resolve("activity/close.png");
background-size: cover;
}
.feature-page .modal {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
margin: 0 auto;
z-index: 1001;
background: rgba(0, 0, 0, 0.5);
display: none;
}
.feature-page .modal .modal-close {
position: absolute;
display: inline-block;
top: 20%;
right: 5%;
width: 45px;
height: 45px;
overflow: hidden;
border-radius: 50px;
background: black;
opacity: 0.5;
z-index: 100;
}
.feature-page .modal .modal-close:before,
.feature-page .modal .modal-close:after {
content: "";
position: absolute;
width: 80%;
top: 50%;
left: 10%;
height: 6px;
margin-top: -3px;
border-radius: 5px;
background: #fff;
}
.feature-page .modal .modal-close:before {
transform: rotate(45deg);
}
.feature-page .modal .modal-close:after {
transform: rotate(-45deg);
}
.feature-page .modal .modal-img {
position: absolute;
height: auto;
top: 20%;
left: 50%;
width: 90%;
transform: translateX(-50%);
}
.feature-page .sidebar {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
margin: 0 auto;
display: none;
background: rgba(0, 0, 0, 0.5);
z-index: 1000;
}
.feature-page .sidebar-content {
position: fixed;
display: block;
top: 50%;
right: 0;
width: 242px;
margin-top: -407px;
z-index: 1001;
}
.feature-page .sidebar-item {
position: relative;
img {
display: block;
width: 100%;
}
a {
position: absolute;
}
}
.feature-page .sidebar-img {
position: fixed;
display: block;
top: 50%;
right: 0;
width: 140px;
height: 150px;
margin-top: -75px;
z-index: 999;
}
.feature-page .over {
position: fixed;
top: 50%;
left: 50%;
width: 100%;
transform: translate(-50%, -50%);
text-align: center;
font-size: 28px;
color: #000;
p {
margin-bottom: 20px;
}
}
... ...
.video {
position: fixed;
top: -100%;
width: 100%;
height: 360px;
z-index: 3;
&.android {
top: 30%;
z-index: 1002;
}
}
.video-android-bg {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
z-index: 1001;
background: #000;
opacity: 0.7;
}
.video-android-close {
position: fixed;
top: 26.2%;
right: 10px;
width: 35px;
height: 35px;
z-index: 1003;
background-image: resolve("activity/close.png");
background-size: cover;
}
.product-container {
overflow: hidden;
... ... @@ -56,12 +21,14 @@
height: 257px;
}
.price {
.price,
.vipprice {
line-height: 34px;
height: 34px;
}
.sale-price {
.sale-price,
.vipprice {
font-size: 26px;
}
}
... ... @@ -132,7 +99,7 @@
position: absolute;
left: 0;
top: 0;
width: 40%;
width: 100%;
height: auto;
z-index: 1;
}
... ... @@ -141,11 +108,25 @@
position: absolute;
right: 0;
top: 0;
width: 40%;
width: 100%;
height: auto;
z-index: 1;
}
.vipprice {
line-height: 40px;
height: 40px;
white-space: nowrap;
text-align: center;
font-size: 26px;
color: #000;
}
.vip-price-text {
margin-right: 10px;
font-weight: 500;
}
.price {
font-size: 18px;
line-height: 40px;
... ...
... ... @@ -35,6 +35,13 @@ module.exports = {
}
return JSON.stringify(fp);
},
isLazyLoad: function(type, index, opt) {
if (type !== 'fix' && index > 8) { // 活动页中 不是浮动层及8张图后面的采用懒加载
return opt.fn(this); // eslint-disable-line
} else {
return opt.inverse(this); // eslint-disable-line
}
},
styleFormat: function(styleObj, opts) {
let style = '';
... ... @@ -50,6 +57,11 @@ module.exports = {
}
return style;
},
tabName: function(index, tabnames) {
var names = tabnames.split(',');
return names[index];
},
tabStyle: function(index, count) {
let width = (100 / Number(count)).toFixed(2);
let style = 'height:100%;width:' + width + '%;';
... ...
... ... @@ -102,6 +102,11 @@ exports.processProductList = (list, options) => {
return;
}
// H5 暂时不支持全球购商品,先过滤掉 2017.04.09
if (product.is_global === 'Y') {
return;
}
// 商品信息有问题,则不显示
if (!(
(product.product_id && _.get(product, 'goods_list.length', 0)) || product.recommend_type
... ...