Showing 100 changed files with 2030 additions and 448 deletions

Too many changes to show.

To preserve performance only 100 of 100+ files are displayed.

... ... @@ -7,6 +7,7 @@
'use strict';
const indexModel = require('../models/market');
const _ = require('lodash');
exports.index = (req, res, next) => {
... ... @@ -21,3 +22,26 @@ exports.index = (req, res, next) => {
}).catch(next);
};
/**
* 市场推广活动升级版,自定义下载渠道
* @param req
* @param res
* @param next
*/
exports.v2 = (req, res, next) => {
indexModel.index({
}).then((result) => {
if (_.has(result, 'download[0].url') && req.query.union_type) {
result.download[0].url = result.download[0].url.split('?')[0] +
'?union_type=' + req.query.union_type;
}
res.render('market/market', Object.assign(result, {
title: 'Yoho!Buy 有货'
}));
}).catch(next);
};
... ...
... ... @@ -12,3 +12,27 @@ exports.wechatShare = (req, res, next) => {
res.jsonp(result);
}).catch(next);
};
/**
* 活动页<http://feature.yoho.cn/1101/1101ITEMBOY/index.html?title=%E7%94%B7%E7%94%9F%E5%88%86%E4%BC%9A%E5%9C%BA&share_id=814&mkt_code=1011111#a_01>
* <xiaoxiao.hao@yoho.cn>
* 2016/07/13
*/
// 活动页保存相应cookie的值
exports.feature = (req, res) => {
let mktCode = req.query.mkt_code || false;
// 下载浮层,下载按钮会用到该参数
if (mktCode) {
res.cookie('mkt_code', mktCode, {
domain: '.yohobuy.com',
path: '/'
});
res.cookie('unionTypeYas', mktCode, {
path: '/'
});
}
res.json({mktCode: mktCode});
};
... ...
... ... @@ -17,18 +17,20 @@ const getPageInfo = (pageInfo) => {
dest.activityID = pageInfo.id;
dest.title = pageInfo.data.h5Title;
dest.activityDesc = pageInfo.data.activityDesc;
dest.formatActivityDesc = pageInfo.data.formatActivityDesc;
dest.couponPic = pageInfo.data.couponPic;
dest.oldUserCouponPic = pageInfo.data.oldUserCouponPic;
dest.mobile = pageInfo.data.mobile;
dest.wechatShare = true;
dest.secondScreenPic = pageInfo.data.secondScreenPic;
dest.activityEndPic = pageInfo.data.activityEndPic;
// 强制活动开始,活动上线产品要求这样设置
pageInfo.data.flag = 1;
if (pageInfo.data.flag === 1) {
dest.bgImg = pageInfo.data.activityNormalPic;
} else {
if (pageInfo.data.flag === 3 || pageInfo.data.flag === 4) {
// flag为3 表示活动结束 , 4 表示未开始
dest.bgImg = pageInfo.data.activityEndPic;
dest.ended = true;
} else {
dest.bgImg = pageInfo.data.activityNormalPic;
}
dest.message = pageInfo.data.returnMsg;
}
... ... @@ -91,7 +93,7 @@ exports.getCoupon = (data) => {
method: 'wap.order.drawOrderShareCoupon'
},
// 处理完成后,发给后端
// 处理完成后,发给后端
phoneData = Object.assign(defaultParam, data);
return api.get('', phoneData).then(result => {
... ... @@ -108,10 +110,10 @@ exports.registerAndSendCoupon = (data) => {
method: 'wap.order.registerAndSendCoupon'
},
// 处理完成后,发给后端
// 处理完成后,发给后端
verifyData = Object.assign(defaultParam, data);
return api.get('', verifyData).then(result => {
return getUserStatus(result);
}); // 所有数据返回一个 Promise,方便 Promise.all 调用
}); // 所有数据返回一个 Promise,方便 Promise.all 调用
};
... ...
... ... @@ -71,6 +71,7 @@ router.get('/invite', invite.checkType, invite.index);
router.get('/invite/index', invite.checkType, invite.index);
router.get('/market', market.index); // 市场推广活动
router.get('/market/v2', market.v2); // 市场推广活动升级版,自定义下载渠道
router.get(/\/invite\/share_([\d]+)_([\d]+)_([\d]+).html/, invite.checkType, invite.share);
... ... @@ -116,4 +117,7 @@ router.get('/vip-day1028/crazy-luck', vipDay1028.beforeIn, vipDay1028.crazyLuck)
router.post('/vip-day1028/signin.json', vipDay1028.beforeIn, vipDay1028.signin);
router.post('/vip-day1028/isStudent', vipDay1028.beforeIn, vipDay1028.checkIsStudent);
// 获取活动页传来的参数
router.get('/wechat/1111', wechat.feature);
module.exports = router;
... ...
... ... @@ -2,6 +2,9 @@
<div class="receive-coupon-page">
<div class="bg-contain">
<img src="{{image bgImg 640 1136}}">
{{#if secondScreenPic}}
<img src="{{image secondScreenPic}}">
{{/if}}
</div>
<p class="hidden" id="orderCode">{{ordercode}}</p>
<p class="hidden" id="oldUserCouponPic">{{image oldUserCouponPic}}</p>
... ... @@ -57,6 +60,7 @@
</div>
<div class="tip-wrap hidden">
<img src="{{image activityEndPic 640 1136}}">
<div class="tip fail">
<div class="header">
</div>
... ... @@ -78,7 +82,12 @@
<div class="mask hidden"></div>
<div class="dialog hidden" id="message">
<span class="close"></span>
{{{activityDesc}}}
<div class="activity-message">
<h3>活动说明</h3>
<div class="message">
{{{formatActivityDesc}}}
</div>
</div>
</div>
... ...
/**
* 支付成功页
* @author: jing.li<jing.li@yoho.cn>
* @date: 2016/10/25
*/
'use strict';
const mRoot = '../models';
const payModel = require(`${mRoot}/pay`);
const headerModel = require('../../../doraemon/models/header'); // 头部model
// 货到付款
const payCod = (req, res, next) => {
let headerData = headerModel.setNav({
navTitle: '支付完成'
});
let responseData = {
pageHeader: headerData,
module: 'cart',
page: 'pay',
title: '支付中心 | Yoho!Buy有货 | 潮流购物逛不停'
};
let param = {
uid: req.user.uid,
udid: req.sessionID || require('md5')(req.ip) || 'yoho',
orderCode: req.query.order_code,
contentCode: '05afedf76886d732573f10f7451a1703'
};
// 如果没有uid,跳转到首页
if (!param.uid) {
res.redirect('/');
return;
}
payModel.getPayCod(param).then(result => {
if (result.match === true) {
res.render('pay/pay-cod', Object.assign(responseData, result));
} else {
res.redirect('/');
}
}).catch(next);
};
// 支付宝支付
const payAli = (req, res, next) => {
let headerData = headerModel.setNav({
navTitle: '支付完成'
});
let responseData = {
pageHeader: headerData,
module: 'cart',
page: 'pay',
title: '支付中心 | Yoho!Buy有货 | 潮流购物逛不停'
};
let param = {
uid: req.user.uid,
udid: req.sessionID || require('md5')(req.ip) || 'yoho',
orderCode: req.query.out_trade_no,
contentCode: '05afedf76886d732573f10f7451a1703'
};
// 如果没有uid,跳转到首页
if (!param.uid) {
res.redirect('/');
return;
}
payModel.getPayAli(param).then(result => {
if (result.match === true) {
res.render('pay/pay-ali', Object.assign(responseData, result));
} else {
res.redirect('/');
}
}).catch(next);
};
module.exports = {
payCod,
payAli
};
... ...
... ... @@ -60,13 +60,14 @@ exports.ensure = (req, res, next) => {
let view;
if (paymentInfo.code !== 200) {
if (paymentInfo.message) {
view = {
orderEnsure: false,
message: paymentInfo.message
};
} else {
return Promise.reject(paymentInfo);
view = {
orderEnsure: false,
message: paymentInfo.message
};
// hotfix: nginx 接口限流, code:9999991时没message 信息
if (!view.message) {
view.message = '挤爆啦,系统繁忙';
}
} else {
// 渲染
... ...
/**
<<<<<<< HEAD
* sub app cart
* @author: xuan.chen@yoho.cn<xuan.chen@yoho.cn>
* @date: 2016/09/26
=======
* sub app guang
* @author: Bi Kai<kai.bi@yoho.cn>
* @date: 2016/05/09
>>>>>>> feature/payment
*/
var express = require('express'),
... ...
/**
* 支付成功页
* @author: jing.li<jing.li@yoho.cn>
* @date: 2016/10/25
*/
'use strict';
const api = global.yoho.API;
const serviceAPI = global.yoho.ServiceAPI;
const utils = '../../../utils';
const productProcess = require(`${utils}/product-process`);
// 资源位
const _getBanner = (param) => {
return serviceAPI.get('operations/api/v5/resource/get', {
content_code: param.contentCode
}, {
code: 200
}).then((result) => {
result = result.data;
return result;
});
};
// 购买此商品的用户也购买了
const _getOthersBuy2 = (param) => {
return api.get('', {
method: 'app.recommend.purchased',
productSkn: param.skn,
udid: param.uid,
rec_pos: '100005',
limit: 2
}, {
code: 200
}).then((result) => {
if (result && result.data && result.data.product_list) {
return productProcess.processProductList(result.data.product_list);
}
});
};
// 订单信息
const _getOtherDetail = (param) => {
return api.get('', {
method: 'app.SpaceOrders.detail',
uid: param.uid,
order_code: param.orderCode
}, {
code: 200
}).then((result) => {
return result;
});
};
// 购买此商品的用户也购买了,要先从订单详情获取商品skn
const _getOthersBuy = (param) => {
return api.all([
_getOtherDetail(param)
]).then((result) => {
let goodSkn = '';
if (result && result[0] && result[0].data && result[0].data.order_goods) {
goodSkn = result[0].data.order_goods[0].product_skn;
}
return _getOthersBuy2(Object.assign(param, {skn: goodSkn}));
}).then((result) => {
return result;
});
};
// 货到付款
const getPayCod = (param) => {
return api.all([
_getBanner(param),
_getOthersBuy(param),
_getOtherDetail(param)
]).then((result) => {
let resu = {
match: true,
banner: [],
othersBuy: []
};
if (result && result[0]) {
resu.banner = result[0];
}
if (result && result[1]) {
resu.othersBuy = result[1];
}
if (result && result[2] && result[2].data && result[2].data.payment_amount) {
resu.payment = result[2].data.payment_amount;
} else {
resu.match = false;
}
resu.orderCode = param.orderCode;
resu.orderUrl = '/home/orders/detail?order_code=' + param.orderCode;
return resu;
});
};
// 支付宝支付
const getPayAli = (param) => {
return api.all([
_getBanner(param),
_getOthersBuy(param),
_getOtherDetail(param)
]).then((result) => {
let resu = {
match: true,
banner: [],
othersBuy: []
};
if (result && result[0]) {
resu.banner = result[0];
}
if (result && result[1]) {
resu.othersBuy = result[1];
}
if (result && result[2] && result[2].data && result[2].data.payment_amount) {
resu.payment = result[2].data.payment_amount;
} else {
resu.match = false;
}
resu.orderCode = param.orderCode;
resu.orderUrl = '/home/orders/detail?order_code=' + param.orderCode;
return resu;
});
};
module.exports = {
getPayCod,
getPayAli
};
... ...
... ... @@ -39,7 +39,13 @@ exports.compute = options => {
method: 'app.Seckill.compute',
}, options);
return API.post(url, queryData);
return API.post(url, queryData).then(result => {
// TODO 数据处理
if (result.code === 200 && result.data) {
result.data.yohoCoinCompute = paymentProcess.yohoCoinCompute(result.data);
}
return result;
});
};
... ...
... ... @@ -12,6 +12,7 @@ const authMW = require('../../doraemon/middleware/auth');
const seckill = require(cRoot + '/seckill');
const countController = require(`${cRoot}/count`);
const payController = require(`${cRoot}/pay`);
// Your controller here
router.all('/index/seckill/', authMW);
... ... @@ -21,5 +22,7 @@ router.post('/index/seckill/compute', seckill.compute);
router.post('/index/seckill/submit', seckill.submit);
router.get('/index/count', countController.cartCount);
router.get('/paySuccess/payCod', payController.payCod);// 支付成功,货到付款
router.get('/shopping/pay/aliwapreturn', payController.payAli);// 支付成功,支付宝付款
module.exports = router;
... ...
... ... @@ -112,28 +112,18 @@
</a>
</li>
{{/if}}
<li class="coin" data-yoho-coin="{{yohoCoin}}">
<li class="coin" data-yoho-coin="{{yohoCoinCompute.yohoCoin}}" data-yoho-coin-click={{yohoCoinCompute.yohoCoinClick}}>
<span class="title">有货币</span>
{{#if yohoCoin}}
<span class="desc used {{#unless useYohoCoin}}hide{{/unless}}">已抵¥{{useYohoCoin}}</span>
<span class="desc can-use {{#if useYohoCoin}}hide{{/if}}">可抵¥{{yohoCoin}}</span>
{{#if useYohoCoin}}
<span class="coin-check">
<!-- <em>- ¥ {{useYohoCoin}}</em> -->
<i class="iconfont checkbox icon-cb-radio"></i>
</span>
<span class="desc msg">{{yohoCoinCompute.yohoCoinMsg}}</span>
<span class="yoho-coin-help">?</span>
{{#if yohoCoinCompute.useYohoCoin}}
<span class="coin-check">
<i class="iconfont checkbox icon-cb-radio"></i>
</span>
{{else}}
<span class="coin-check">
<!-- <em style="display: none;">- ¥ {{useYohoCoin}}</em> -->
<i class="iconfont checkbox icon-radio"></i>
</span>
{{/if}}
{{^}}
<span class="not-used coin-check">
无有货币可用
</span>
<span class="coin-check">
<i class="iconfont checkbox icon-radio"></i>
</span>
{{/if}}
</li>
... ... @@ -191,6 +181,18 @@
<a href="javascript:;">提交订单</a>
</div>
<div class="yoho-coin-help-dialog-bg hide"></div>
<div class="yoho-coin-help-dialog hide">
<div class="yoho-coin-title">有货币使用条件:</div>
<div class="yoho-coin-content">
<p>1.订单金额大于20元(含)</p>
<p>2.有货币数量大于{{yohoCoinCompute.yoho_coin_pay_rule.num_limit}}个(含)</p>
<p>3.有货币支付不得超过每笔订单应付金额的{{yohoCoinCompute.yoho_coin_pay_rule.max_pay_rate_desc}}</p>
<p>备注:使用有货币数量为{{yohoCoinCompute.yoho_coin_pay_rule.num_limit}}的整数倍,100有货币抵1元。</p>
</div>
<div class="yoho-coin-footer">知道了</div>
</div>
<input type="hidden" id="product-sku" name="product-sku" value="{{sku}}">
{{#with seckill}}
<input type="hidden" id="activity-id" name="activity-id" value="{{activityId}}">
... ...
<div class="pay-success">
<div class="top-tip">
<div class="img-c"></div>
<p class="ok-tip">恭喜您,付款成功!</p>
</div>
<div class="info-table-c">
<table class="info-table">
<tr>
<td>订单编号</td>
<td>{{orderCode}}</td>
</tr>
<tr>
<td>付款金额</td>
<td>¥{{payment}}</td>
</tr>
<tr>
<td>付款方式</td>
<td>支付宝</td>
</tr>
</table>
</div>
<div class="btn-c">
<a href="/">随便逛逛</a>
<a href="{{orderUrl}}">查看订单</a>
</div>
{{# banner}}
{{#data}}
<a href="{{url}}" class="ad-pic" alt="{{alt}}">
<img src="{{image src 640 200}}" />
</a>
{{/data}}
{{/banner}}
<div class="others-buy clearfix">
<p>购买此商品的用户也购买了</p>
{{# othersBuy}}
{{> common/goods}}
{{/ othersBuy}}
</div>
{{> home/maybe-like}}
</div>
... ...
<div class="pay-success">
<div class="top-tip">
<div class="img-c"></div>
<p class="ok-tip">订单提交成功</p>
<p class="left-tip">您需要在收货时向售货员支付¥{{payment}}</p>
</div>
<div class="info-table-c">
<table class="info-table">
<tr>
<td>订单编号</td>
<td>{{orderCode}}</td>
</tr>
<tr>
<td>付款金额</td>
<td>¥{{payment}}</td>
</tr>
<tr>
<td>付款方式</td>
<td>货到付款</td>
</tr>
</table>
</div>
<div class="btn-c">
<a href="/">随便逛逛</a>
<a href="{{orderUrl}}">查看订单</a>
</div>
{{# banner}}
{{#data}}
<a href="{{url}}" class="ad-pic" alt="{{alt}}">
<img src="{{image src 640 200}}" />
</a>
{{/data}}
{{/banner}}
<div class="others-buy clearfix">
<p>购买此商品的用户也购买了</p>
{{# othersBuy}}
{{> common/goods}}
{{/ othersBuy}}
</div>
{{> home/maybe-like}}
</div>
... ...
... ... @@ -6,6 +6,7 @@
'use strict';
const _ = require('lodash');
const channelModel = require('../models/channel');
const homeModel = require('../../home/models/index');
const footerModel = require('../../../doraemon/models/footer_tab'); // 底部tab
const helpers = global.yoho.helpers;
... ... @@ -152,6 +153,47 @@ let bottomBanner = (req, res, next) => {
}).catch(next);
};
/**
* 店铺推荐收藏状态人数
*/
let shopRecom = (req, res, next) => {
channelModel.shopRecom({
shopIds: req.body.shopIds || '',
uid: req.user.uid || 0,
}).then(result => {
res.send(result);
}).catch(next);
}
/**
* 获取用户vip信息
*/
let userVip = (req, res, next) => {
let uid = req.user.uid;
if (!uid) {
res.json({
code: 555,
msg: '未登录'
});
} else {
homeModel.getGradeGrade(uid, req.query.channel || 1).then(result => {
if (result.code === 200) {
res.json({
code: 200,
current_vip_level: result.data.current_vip_level,
});
} else {
res.json({
code: 500,
msg: '出错了',
})
}
});
}
}
module.exports = {
switchChannel,
index,
... ... @@ -159,5 +201,7 @@ module.exports = {
girls,
kids,
lifestyle,
bottomBanner
};
bottomBanner,
shopRecom,
userVip,
};
\ No newline at end of file
... ...
... ... @@ -8,6 +8,7 @@ const utils = '../../../utils';
const contentCodeConfig = require('../../../config/content-code');
const _ = require('lodash');
const api = global.yoho.ServiceAPI;
const API = global.yoho.API;
const logger = global.yoho.logger;
const resourcesProcess = require(`${utils}/resources-process`);
... ... @@ -298,8 +299,20 @@ let getBottomBannerData = (gender) => {
});
};
/**
* 获取店铺推荐收藏和人数
*/
let shopRecom = (params) => {
return API.get('', {
method: 'app.shops.floorNewInfo',
shop_ids: params.shopIds,
uid: params.uid,
});
}
module.exports = {
getChannelData,
getChannelSwitchData,
getBottomBannerData
getBottomBannerData,
shopRecom,
};
... ...
... ... @@ -29,4 +29,7 @@ router.post('/brands/searchAsync', brandController.searchAsync); // 品牌搜索
router.post('/brands/addBrandSearch', brandController.addBrandSearch); // 添加品牌搜索记录
router.get('/brands/delBrandHistory', brandController.delBrandHistory); // 删除品牌搜索记录
// 5.2新楼层功能
router.post('/channel/shopRecom', channel.shopRecom); // 店铺推荐收藏状态
router.post('/channel/userVip', channel.userVip)
module.exports = router;
... ...
... ... @@ -14,7 +14,9 @@
{{/announcement}} --}}
{{! 中间banner}}
{{#if singleImage}}
<div data-id="{{template_id}}">
{{> resources/banner}}
</div>
{{/if}}
{{! 两个小图}}
{{#if smallPic}}
... ... @@ -53,7 +55,7 @@
{{> resources/plus-star}}
{{/if}}
{{! 新人专享}}
{{#if newUserFloor}}
{{#if oldNewUserFloor}}
{{> resources/fresh-only}}
{{/if}}
{{! 秒杀}}
... ... @@ -72,4 +74,32 @@
{{#if sixLinesFloor}}
{{> resources/six-lines-floor}}
{{/if}}
{{! vip专属}}
{{#if vipUse}}
{{> resources/vip-only}}
{{/if}}
{{! 店铺推荐}}
{{#if shopRecommend}}
{{> resources/shop-recommand}}
{{/if}}
{{! 新新人专享}}
{{#if newUserFloor}}
{{> resources/new-user-floor}}
{{/if}}
{{! 人气单品}}
{{#if popularSingleProduct}}
{{> resources/hot-single}}
{{/if}}
{{! SALE}}
{{#if sale1T1L4R}}
{{> resources/sale-floor}}
{{/if}}
{{! 新品首发楼层}}
{{#if newProductFloor}}
{{> resources/new-first}}
{{/if}}
{{! 分隔楼层}}
{{#if divideImage}}
{{> resources/divide-image}}
{{/if}}
{{/content}}
... ...
... ... @@ -118,8 +118,10 @@ const _pageArticleContent = (articleContent, isApp, gender) => {
let arr = [];
goods.list.forEach((mini) => {
skns.push(mini.id);
arr[mini.id] = mini.src;
if (mini) {
skns.push(mini.id);
arr[mini.id] = mini.src;
}
});
// 通过SKN获取商品信息
... ...
... ... @@ -12,10 +12,6 @@
{{/if}}
<!--/tab-nav-->
{{#if isApp}}
<div class='empty-height'></div>
{{/if}}
<div class="plusstar-resources">
<!--资源位数据模板-->
</div><!--/plusstar-resources-->
... ...
... ... @@ -15,6 +15,17 @@ const _serverCrash = (res, params) => {
res.render('installment/server-crash', params);
};
const _banksInit = () => {
const banks = ['农业银行', '中国银行', '工商银行', '建设银行', '光大银行', '兴业银行', '邮储银行', '民生银行', '中信银行', '广发银行'];
if (new Date() >= new Date('2016-10-18 00:00:00')) {
// 2016年10月12日至17日 平安银行业务暂停(平安银行期间不支持服务)
banks.push('平安银行');
}
return banks;
};
// 还款列表公共处理块
const _repaymentList = (req, res, opt, params) => {
params = _.assign({
... ... @@ -285,24 +296,29 @@ const getRepayRecord = (req, res) => {
// 账号管理
const account = (req, res) => {
var url = req.yoho.isApp || req.cookies.appVersion ? '/home/installment/account' : '/home/installment/bank-card';
res.render('installment/account', {
module: 'home',
page: 'account',
title: '账号管理',
isInstallmentPage: true,
posId: 7,
url: helpers.appUrlFormat('/home/installment/bank-card', 'go.instalmentMyCard')
url: helpers.appUrlFormat(url, 'go.instalmentMyCard')
});
};
// 添加新银行卡
const bindCard = (req, res) => {
const banks = _banksInit();
res.render('installment/bind-card', {
module: 'home',
page: 'bind-card',
title: req.query.title || '使用新卡还款',
bindCard: {
userName: req.query.name
userName: req.query.name,
banks: banks.join('、')
},
isInstallmentPage: true
});
... ... @@ -325,12 +341,7 @@ const postAccount = (req, res) => {
};
const startingService = (req, res) => {
const banks = ['农业银行', '中国银行', '工商银行', '建设银行', '光大银行', '兴业银行', '邮储银行', '民生银行', '中信银行', '广发银行'];
if (new Date() >= new Date('2016-10-18 00:00:00')) {
// 2016年10月12日至17日 平安银行业务暂停(平安银行期间不支持服务)
banks.push('平安银行');
}
const banks = _banksInit();
res.render('installment/starting-service', {
module: 'home',
... ... @@ -631,7 +642,7 @@ const cardDetail = (req, res) => {
let uid = req.cookies.installmentUid;
let cardIdNo = req.query.cardIdNo;
installmentModel.getCardDetail(uid, cardIdNo).then(result => {
installmentModel.getCardDetail(uid, cardIdNo).then((result) => {
res.render('installment/card-detail', {
module: 'home',
page: 'card-detail',
... ...
... ... @@ -453,5 +453,6 @@ module.exports = {
recordContent,
delRecord,
getGrade,
getPreferential
getPreferential,
getGradeGrade,
};
... ...
... ... @@ -498,7 +498,7 @@ const getCardDetail = (uid, cardIdNo) => {
return _processCardDetail(result.data);
} else {
logger.error('get getBankCards data return code is not 200');
return '';
return Promise.reject(result);
}
});
};
... ...
... ... @@ -8,6 +8,7 @@
<li>
<label>银行卡</label>
<input id="cardNo" name="cardNo" type="tel" placeholder="请输入本人银行卡号" size="26" maxlength="23">
<span class="iconfont notice">&#xe639;</span>
</li>
<li id="bank-desc" style="display: none;">
<div class="bank-info">
... ... @@ -20,8 +21,19 @@
<input type="number" placeholder="请输入银行预留手机号" id="mobile" name="mobile" pattern="\d*" maxlength="11">
</li>
</ul>
<a href="" class="open-btn disabled">下一步</a>
<div class="open-btn disabled">下一步</div>
<a href="" class="jumpResult">&nbsp;</a>
<div class="installment-overdue-notice">
<div class="mask-bg"></div>
<div class="notice-area">
<div class="notice-cont">
<h2>支持银行</h2>
<p>{{banks}}</p>
</div>
<div class="think-ok">我知道了</div>
</div>
</div>
{{/bindCard}}
<div class="success">
... ...
... ... @@ -23,7 +23,7 @@
</ul>
<div class="tip-cont">
{{#if isMaster}}
<p>如果您更换银行预留手机号,请先新增其他还款银行卡,并将新增银行卡切换为主卡,并解除绑定此卡,再次重新绑定即可。</p>
<p>如果您更换银行预留手机号,请先新增其他还款银行卡,并将新增银行卡切换为主卡。然后解除绑定此卡,重新绑定即可。</p>
{{else}}
<p>如果您更换银行预留手机号,请先将银行卡解除绑定,再次重新绑定即可。</p>
... ...
... ... @@ -3,7 +3,7 @@
<ul id="order-nav" class="order-nav clearfix">
{{#each navs}}
<li class="tap-hightlight {{#if active}}active{{/if}}" data-type="{{typeId}}">
<a href="{{url}}">{{name}}</a>
<a class="nav-tap" data-url="{{url}}">{{name}}</a>
</li>
{{/each}}
</ul>
... ...
<div class="notice-wrap clearfix">
<div class="notice" data-time="{{time}}">
<span class="notice-icon"></span>
{{#list}}
<a class="notice-item item-{{@index}}" href="{{url}}">
{{title}}
</a>
{{/list}}
<div class="swiper-wrapper">
{{#list}}
<a class="notice-item swiper-slide swiper-no-swiping item-{{@index}}" href="{{url}}">
{{title}}
</a>
{{/list}}
</div>
</div>
</div>
... ...
... ... @@ -10,6 +10,7 @@ const _ = require('lodash');
const helpers = global.yoho.helpers;
const service = require('../models/back-service');
const captchaService = require('../models/captcha-service');
const SIGN_IN = helpers.urlFormat('/passport/login');
... ... @@ -150,18 +151,93 @@ const indexMobilePage = (req, res, next) => {
isPassportPage: true,
backMobile: true,
countrys: result.data,
areaCode: '+86'
areaCode: '+86',
verifySrc: helpers.urlFormat('/passport/back/generatecodeimg.png', {t: Date.now()})
}));
})
.catch(next);
};
/**
* 生成验证码
* @param req
* @param res
*/
const generateCodeImg = (req, res) => {
let verifyCodeImg = captchaService.generateCaptcha(109, 50, 4);
if (verifyCodeImg) {
if (req.session.backupCaptch) {
req.session.backupCaptch.code = verifyCodeImg.text;
req.session.backupCaptch.verifyResult = false;
} else {
req.session.backupCaptch = {
code: verifyCodeImg.text,
verifyResult: false
};
}
res.set('Cache-Control', 'no-cache').send(verifyCodeImg.image);
}
};
/**
* 发送手机验证码
*/
const sendCodeToMobileAPI = (req, res, next) => {
let verifyCode = req.body.verifyCode || '';
let phoneNum = req.body.phoneNum || '';
let areaCode = req.body.areaCode || '86';
/* 如果设置了冻结时间,验证 */
if (_.has(req.session, 'backupCaptch.timeout')) {
let untilTime = (parseInt(req.session.backupCaptch.timeout, 10) -
parseInt(Date.now(), 10)) / 1000 / 60;
if (parseInt(Date.now(), 10) < parseInt(req.session.backupCaptch.timeout, 10)) {
return res.json({
code: 401,
message: '请' + (parseInt(untilTime, 10) + 1) + '分钟后尝试!'
});
}
}
/* 如果设置了验证次数,验证是否合法,验证次数减 1;没有,设置验证次数 */
if (_.has(req.session, 'backupCaptch.useTime')) {
if (parseInt(req.session.backupCaptch.useTime, 10) <= 0) {
/* 如果超过验证次数,冻结 5 分钟,更新验证次数 */
req.session.backupCaptch.timeout = Date.now() + 5 * 60 * 1000;
req.session.backupCaptch.useTime = 5;
return res.json({
code: 401,
message: '请5分钟后尝试!'
});
}
req.session.backupCaptch.useTime = req.session.backupCaptch.useTime - 1;
} else {
req.session.backupCaptch.useTime = 5;
}
if (verifyCode) {
if (verifyCode.toString() === _.get(req, 'session.backupCaptch.code', '').toString()) {
req.session.backupCaptch.verifyResult = true;
} else {
return res.json({
code: 400,
message: '验证码输入错误'
});
}
} else if (!req.session.backupCaptch.verifyResult) {
return res.json({
code: 409,
message: '非法请求!',
refer: helpers.urlFormat('/')
});
}
let ERR = {
code: 400,
message: '输入手机号码出错'
... ... @@ -198,6 +274,11 @@ const verifyCodeByMobilePage = (req, res) => {
let phoneNum = req.query.phoneNum || '';
let areaCode = req.query.areaCode || '86';
/* 用户直接进入第二个页面的情况 */
if (!_.get(req, 'session.backupCaptch.verifyResult')) {
return res.redirect(helpers.urlFormat('/'));
}
res.render('back/mobile-code', Object.assign({
module: 'passport',
page: 'back-code',
... ... @@ -208,8 +289,8 @@ const verifyCodeByMobilePage = (req, res) => {
isPassportPage: true,
backCode: true,
areaCode: areaCode,
phoneNum: phoneNum
phoneNum: phoneNum,
verifySrc: helpers.urlFormat('/passport/back/generatecodeimg.png', {t: Date.now()})
}));
};
... ... @@ -309,5 +390,6 @@ module.exports = {
verifyCodeByMobilePage,
verifyCodeByMobileAPI,
setNewPasswordByMobilePage,
setNewPasswordByMobileAPI
setNewPasswordByMobileAPI,
generateCodeImg
};
... ...
... ... @@ -13,8 +13,49 @@ const sign = global.yoho.sign;
const cookie = global.yoho.cookie;
const RegService = require('../models/reg-service');
const AuthHelper = require('../models/auth-helper');
const captchaService = require('../models/captcha-service');
/*
session 结构
phoneReg: {
step //当前步骤
captcha // step1 的校验码
count: 5 // 默认可以重发5次, 当count: 0, 冻结30min,之后解冻
expire // 解冻时间
}
*/
/**
* 步骤校验
* step: 预期步骤
*/
let guardStep = function(step) {
return (req, res, next) => {
let curStep = _.get(req.session, 'phoneReg.step');
if (curStep !== step) {
if (req.xhr) {
return res.json({
code: 400,
refer: '/reg.html'
});
} else {
return res.redirect('/reg.html');
}
}
return next();
};
};
/**
* Step1: 输入手机号码 + 验证码
*/
let index = (req, res) => {
if (req.user.uid) {
return res.redirect(req.get('refer') || '/');
}
// 设置注册有效时间30分钟, 防机器刷
// req.session.REG_EXPIRE = Date.now() + 1800000;
let refer = req.query.refer;
... ... @@ -23,17 +64,27 @@ let index = (req, res) => {
domain: 'yohobuy.com'
});
// session init
_.set(req.session, 'phoneReg.step', 1);
if (req.session.phoneReg.count == null) { // eslint-disable-line
req.session.phoneReg.count = 5;
}
res.render('reg/index', {
module: 'passport',
page: 'reg',
title: '注册',
backUrl: 'javascript:history.go(-1)', // eslint-disable-line
captchaUrl: helpers.urlFormat('/passport/reg/captcha.png', {t: Date.now()}),
headerText: '注册', // 头部信息
isPassportPage: true, // 模板中模块标识
areaCode: '+86', // 默认的区号
countrys: RegService.getAreaData() // 地区信息列表
});
};
let verifyMobile = (req, res, next) => {
let data = {
code: 400,
... ... @@ -43,6 +94,28 @@ let verifyMobile = (req, res, next) => {
let mobile = +req.body.phoneNum;
let area = +(req.body.areaCode || 86);
let captcha = (req.body.captcha || '').trim();
let diffCaptcha = _.get(req.session, 'phoneReg.captcha');
// error case: 没有验证码
if (!diffCaptcha) {
return res.json({
code: 400,
message: '请求失败',
refreshCaptcha: true
});
}
delete req.session.phoneReg.captcha; // captcha 一次性
// error case: 验证码不匹配
if (captcha !== diffCaptcha) {
return res.json({
code: 400,
message: '校验码不正确',
refreshCaptcha: true
});
}
// 判断参数是否合法
if (!_.isNumber(mobile) || !_.isNumber(area)) {
... ... @@ -58,6 +131,7 @@ let verifyMobile = (req, res, next) => {
// return res.json(data);
// }
// 向手机发送注册验证码
RegService.sendCodeToMobile(area, mobile).then((result) => {
if (!result.code) {
... ... @@ -68,6 +142,14 @@ let verifyMobile = (req, res, next) => {
if (result.code === 200) {
let token = sign.makeToken(mobile);
_.set(req.session, 'phoneReg.step', 2); // go step 2
--req.session.phoneReg.count;
// count is 0, will freeze;
if (!req.session.phoneReg.count) {
_.set(req.session, 'phoneReg.expire', Date.now() + 5 * 60 * 1000);
}
result.data = helpers.urlFormat('/passport/reg/code', {
token: token,
phoneNum: mobile,
... ... @@ -78,6 +160,11 @@ let verifyMobile = (req, res, next) => {
return res.json(result);
}).catch(next);
};
/**
* Step2: 校验 手机验证码
*/
let codeAction = (req, res, next) => {
let token = req.query.token;
let mobile = +req.query.phoneNum;
... ... @@ -103,6 +190,36 @@ let codeAction = (req, res, next) => {
serviceUrl: 'http://chat8.live800.com/live800/chatClient/chatbox.jsp?companyID=620092&configID=149091&jid=8732423409&info=' // 在线客服
});
};
let sendCodeBusyBoy = (req, res, next) => {
let count = _.get(req.session, 'phoneReg.count');
let expire = _.get(req.session, 'phoneReg.expire');
if (count) {
return next();
} else {
/*
如果 count === 0
1. 没过解冻期
2. 过了解冻期, count reset to 5
*/
let now = Date.now();
if (now > expire) {
_.set(req.session, 'phoneReg.count', 5);
return next();
} else {
return res.json({
code: 400,
message: '发送次数太多, 5分钟稍后再试'
});
}
}
};
let sendCode = (req, res, next) => {
let data = {
code: 400,
... ... @@ -129,7 +246,19 @@ let sendCode = (req, res, next) => {
// 向手机发送注册验证码
RegService.sendCodeToMobile(area, mobile).then((result) => {
return result.code ? res.json(result) : res.json(data);
let code = _.get(result, 'code');
if (code) {
--req.session.phoneReg.count;
// count is 0, will freeze;
if (!req.session.phoneReg.count) {
_.set(req.session, 'phoneReg.expire', Date.now() + 5 * 60 * 1000);
}
return res.json(result);
} else {
return res.json(data);
}
}).catch(next);
};
... ... @@ -164,25 +293,31 @@ let verifyCode = (req, res, next) => {
return res.json(data);
}
// 返回跳转到设置密码的链接
if (result.code === 200) {
let token = sign.makeToken(mobile);
result.data = helpers.urlFormat('/passport/reg/password', {
token: token,
phoneNum: mobile,
areaCode: area,
smsCode: code
});
} else if (result.code === 404) {
result.message = '验证码错误'; // 统一验证提示
let resultCode = _.get(result, 'code');
let token = sign.makeToken(mobile);
switch (resultCode) {
case 200:
_.set(req.session, 'phoneReg.step', 3); // go step 3
result.data = helpers.urlFormat('/passport/reg/password', {
token: token,
phoneNum: mobile,
areaCode: area,
smsCode: code
});
break;
case 404:
default:
result = data;
}
return res.json(result);
}).catch(next);
};
/**
* Step3: set Password
*/
let passwordAction = (req, res, next) => {
let token = req.query.token;
let mobile = +req.query.phoneNum;
... ... @@ -190,12 +325,12 @@ let passwordAction = (req, res, next) => {
let smsCode = +req.query.smsCode;
// 判断是否允许访问, 不允许则跳转到错误页面
// if (!smsCode || !_.isString(token) || !_.isNumber(mobile) || !_.isNumber(area) || !sign.verifyToken(mobile, token)) {
// return next({
// code: 403,
// message: 'error token, mobile or verifyCode'
// });
// }
if (!smsCode || !_.isString(token) || !_.isNumber(mobile) || !_.isNumber(area) || !sign.verifyToken(mobile, token)) {
return next({
code: 403,
message: 'error token, mobile or verifyCode'
});
}
res.render('reg/password', {
page: 'password',
... ... @@ -210,7 +345,6 @@ let passwordAction = (req, res, next) => {
});
};
let setPassword = (req, res, next) => {
let data = {
code: 400,
... ... @@ -267,6 +401,8 @@ let setPassword = (req, res, next) => {
refer = '/home';
}
delete req.session.phoneNum;
return res.json({
code: 200,
message: '注册成功',
... ... @@ -278,12 +414,29 @@ let setPassword = (req, res, next) => {
}).catch(next);
};
/**
* 生成 校验码
*/
const genCaptcha = (req, res) => {
let captcha = captchaService.generateCaptcha(90, 52, 4);
_.set(req.session, 'phoneReg.captcha', captcha.text);
res.type('png')
.set('Cache-Control', 'no-cache')
.status(200)
.send(captcha.image);
};
module.exports = {
guardStep,
sendCodeBusyBoy,
index,
verifyMobile,
code: codeAction,
sendCode,
verifyCode,
password: passwordAction,
setPassword
setPassword,
genCaptcha
};
... ...
/* eslint no-unused-vars: ["error", { "args": "none" }] */
'use strict';
const _ = require('lodash');
const helpers = global.yoho.helpers;
const cookie = global.yoho.cookie;
const RegService = require('../models/reg-service');
const PhoneService = require('../models/phone-service');
const AuthHelper = require('../models/auth-helper');
const captchaService = require('../models/captcha-service');
// constrant
const CODE_REQUIRED = '请输入校验码';
... ... @@ -23,7 +25,7 @@ exports.beforeIn = (req, res, next) => {
});
if (!req.xhr && req.user.uid) {
return res.redirect(req.cookies.refer);
return res.redirect(req.cookies.refer || '/');
}
next();
... ... @@ -31,6 +33,12 @@ exports.beforeIn = (req, res, next) => {
// 短信登录 第一步: 展现页面
const _step1 = (req, res, next) => {
_.set(req.session, 'smsLogin.step', 1);
if (req.session.smsLogin.count == null) { // eslint-disable-line
req.session.smsLogin.count = 5;
}
let template = 'sms/login';
let viewData = {
module: 'passport',
... ... @@ -38,6 +46,7 @@ const _step1 = (req, res, next) => {
title: '手机短信登录',
isPassportPage: true,
headerText: '手机号码快捷登录',
captchaUrl: helpers.urlFormat('/passport/sms_login/captcha.png', {t: Date.now()}),
areaCode: '+86', // 默认的区号
countrys: RegService.getAreaData() // 地区信息列表
};
... ... @@ -58,7 +67,7 @@ const _step2 = (req, res, next) => {
title: '手机短信登录',
isPassportPage: true,
headerText: '手机号码快捷登录',
canResend: interval < Date.now(),
countdown: Math.ceil((interval - Date.now()) / 1000),
mobile,
area
};
... ... @@ -83,7 +92,7 @@ const _step3 = (req, res, next) => {
// 短信 登录
exports.loginPage = (req, res, next) => {
let step = Number(req.query.step) || 1;
let smsLoginStep = req.session.smsLoginStep || 1;
let smsLoginStep = _.get(req.session, 'smsLogin.step', 1);
if (step === 2 && smsLoginStep !== 2) {
return res.redirect(req.path);
... ... @@ -109,23 +118,63 @@ exports.loginPage = (req, res, next) => {
exports.tokenBefore = (req, res, next) => {
let area = req.query.area = (req.query.area || '').trim();
let mobile = req.query.mobile = (req.query.mobile || '').trim();
let step = _.get(req.session, 'smsLogin.step');
let count = _.get(req.session, 'smsLogin.count');
let interval = _.get(req.session, 'smsLogin.interval');
let captcha1 = _.get(req.session, 'smsLogin.captcha');
let captcha2 = (req.query.captcha || '').trim();
if (!req.xhr) {
return next(404);
}
if (req.session.smsLogin && req.session.smsLogin.interval > Date.now()) {
if ([area, mobile].some(val => val === '')) {
return res.json({
code: 429,
message: TOO_MANY
code: 401,
message: '手机号 必填'
});
}
delete req.session.smsLogin.captcha; // 图形验证码 一次性
if ([area, mobile].some(val => val === '')) {
// step1 要 校验图形验证码
if (step === 1) {
if (!captcha2) {
return res.json({
code: 400,
message: '请填写验证码'
});
}
if (captcha1 !== captcha2) {
return res.json({
code: 400,
message: VERIFY_ERROR
});
}
}
let now = Date.now();
// 重发次数用完了, 回冻结5min
// 1. 过了冻结期, count 重设为 5次
// 2. 没过冻结期, end
// 没有用完, 判断是否请求太频繁
if (!count) {
if (interval > now) {
return res.json({
code: 400,
message: TOO_MANY,
during: Math.ceil((interval - now) / 1000)
});
} else {
_.set(req.session, 'smsLogin.count', 5);
}
} else if (interval > now) {
return res.json({
code: 401,
message: '请求参数,无法处理'
code: 429,
message: TOO_MANY
});
}
... ... @@ -139,12 +188,18 @@ exports.token = (req, res, next) => {
PhoneService.sendSMS(mobile, area, 1).then(result => {
if (result.code === 200) {
req.session.smsLogin = {
interval: Date.now() + 60 * 1000, // 重发验证码 间隔: 60s
area,
mobile
};
req.session.smsLoginStep = 2; // 进入短信登录 step2
_.set(req.session, 'smsLogin.step', 2);
_.set(req.session, 'smsLogin.area', area);
_.set(req.session, 'smsLogin.mobile', mobile);
--req.session.smsLogin.count;
if (!req.session.smsLogin.count) {
_.set(req.session, 'smsLogin.interval', Date.now() + 5 * 60 * 1000);
} else {
_.set(req.session, 'smsLogin.interval', Date.now() + 60 * 1000);
}
result.redirect = '/passport/sms_login?step=2';
res.json(result);
... ... @@ -157,8 +212,9 @@ exports.token = (req, res, next) => {
exports.checkBefore = (req, res, next) => {
let code = req.query.code = (req.query.code || '').trim();
let step = _.get(req.session, 'smsLogin.step');
if (!req.xhr && req.session.smsLoginStep !== 2) {
if (!req.xhr && step !== 2) {
return next(404);
}
... ... @@ -214,7 +270,7 @@ exports.check = (req, res, next) => {
// 手机号码 没注册
if (r1.data.is_register !== 'Y') {
redirect = '/passport/sms_login?step=3';
req.session.smsLoginStep = 3;
_.set(req.session, 'smsLogin.step', 3);
res.json({
code: 200,
... ... @@ -247,7 +303,6 @@ exports.check = (req, res, next) => {
});
delete req.session.smsLogin;
delete req.session.smsLoginStep;
})
.catch(error => {
res.json(error);
... ... @@ -259,7 +314,9 @@ exports.check = (req, res, next) => {
// AJAX 短信登录 设置密码 in step3
exports.password = (req, res, next) => {
if (req.session.smsLoginStep !== 3) {
let step = _.get(req.session, 'smsLogin.step');
if (step !== 3) {
return next();
}
... ... @@ -269,9 +326,8 @@ exports.password = (req, res, next) => {
message: BAD_PASSWORD
};
let smsLogin = req.session.smsLogin || {};
let mobile = smsLogin.mobile;
let area = smsLogin.area;
let mobile = _.get(req.session, 'smsLogin.mobile');
let area = _.get(req.session, 'smsLogin.area');
let password = (req.body.password || '').trim();
let smsCode = +req.body.smsCode || 0;
... ... @@ -306,11 +362,23 @@ exports.password = (req, res, next) => {
res.json({
code: 200,
message: LOGIN_SUCCSS,
redirect: req.cookies.refer
redirect: req.cookies.refer || '/'
});
delete req.session.smsLogin;
delete req.session.smsLoginStep;
}).catch(next);
};
/**
* 生成 校验码
*/
exports.genCaptcha = (req, res) => {
let captcha = captchaService.generateCaptcha(90, 52, 4);
_.set(req.session, 'smsLogin.captcha', captcha.text);
res.type('png')
.set('Cache-Control', 'no-cache')
.status(200)
.send(captcha.image);
};
... ...
/**
* Created by TaoHuang on 2016/7/1.
*/
'use strict';
const _ = require('lodash');
const Captchapng = require('captchapng');
exports.generateCaptcha = (width, height, length) => {
let min = Math.pow(10, (length - 1 || 1));
let max = Math.pow(10, (length - 1 || 1)) * 9;
let token = '' + _.random(min, max);
let png = new Captchapng(width, height, token);//
png.color(0, 0, 0, 0); // First color: background (red, green, blue, alpha)
png.color(80, 80, 80, 255); // Second color: paint (red, green, blue, alpha)
return {
image: new Buffer(png.getBase64(), 'base64'),
text: token
};
};
... ...
... ... @@ -12,6 +12,7 @@ const login = require(cRoot + '/login');
const back = require(cRoot + '/back');
const bind = require(cRoot + '/bind');
const reg = require(cRoot + '/reg');
const smsLogin = require(cRoot + '/sms');
const update = require(cRoot + '/update');
const agreement = require(cRoot + '/app-agreement');
... ... @@ -36,15 +37,16 @@ router.get('/passport/international', login.common.beforeLogin, login.local.inte
router.post('/passport/login/auth', login.local.login);
// SMS 短信
// router.use('/passport/sms_login', login.common.beforeLogin, smsLogin.beforeIn);
// router.get('/passport/sms_login', smsLogin.loginPage);
// router.get('/passport/sms_login/token.json',
// smsLogin.tokenBefore,
// smsLogin.token); // only ajax;
// router.get('/passport/sms_login/check.json',
// smsLogin.checkBefore,
// smsLogin.check); // only ajax
// router.post('/passport/sms_login/password.json', smsLogin.password);
router.use('/passport/sms_login', login.common.beforeLogin, smsLogin.beforeIn);
router.get('/passport/sms_login', smsLogin.loginPage);
router.get('/passport/sms_login/token.json',
smsLogin.tokenBefore,
smsLogin.token); // only ajax;
router.get('/passport/sms_login/check.json',
smsLogin.checkBefore,
smsLogin.check); // only ajax
router.post('/passport/sms_login/password.json', smsLogin.password);
router.get('/passport/sms_login/captcha.png', smsLogin.genCaptcha);
// 微信登录
router.get('/passport/login/wechat', login.common.beforeLogin, login.wechat.login);
... ... @@ -84,12 +86,13 @@ router.post('/passport/bind/changeMobile', bind.changeMobile);
* 注册
*/
router.get('/passport/reg/index', reg.index);
router.post('/passport/reg/verifymobile', reg.verifyMobile);
router.get('/passport/reg/code', reg.code);
router.post('/passport/reg/sendcode', reg.sendCode);
router.post('/passport/reg/verifycode', reg.verifyCode);
router.get('/passport/reg/password', reg.password);
router.post('/passport/reg/setpassword', reg.setPassword);
router.get('/passport/reg/captcha.png', reg.genCaptcha);
router.post('/passport/reg/verifymobile', reg.sendCodeBusyBoy, reg.verifyMobile);
router.get('/passport/reg/code', reg.guardStep(2), reg.code);
router.post('/passport/reg/sendcode', reg.guardStep(2), reg.sendCodeBusyBoy, reg.sendCode);
router.post('/passport/reg/verifycode', reg.guardStep(2), reg.verifyCode);
router.get('/passport/reg/password', reg.guardStep(3), reg.password);
router.post('/passport/reg/setpassword', reg.guardStep(3), reg.setPassword);
/**
* 密码找回
... ... @@ -101,6 +104,7 @@ router.get('/passport/back/success', back.backSuccessByEmailPage);// 邮箱找
router.get('/passport/back/mobile', back.indexMobilePage);// 输入手机号找回密码页面
router.get('/passport/back/mobilecode', back.verifyCodeByMobilePage);// 输入手机验证码页面
router.get('/passport/back/generatecodeimg.png', back.generateCodeImg);// 生成图片验证码
router.post('/passport/back/sendcode', back.sendCodeToMobileAPI);// 发送手机验证码
router.post('/passport/back/verifycode', back.verifyCodeByMobileAPI);// 校验手机验证码
... ...
... ... @@ -6,6 +6,12 @@
<span id="area-code" class="area-code">{{areaCode}}</span>
<input id="phone-num" class="input phone-num" type="text" placeholder="手机号">
</div>
<div class="passport-captcha row">
<div class="passport-captcha-img"><img id="verify-code-img" src="{{verifySrc}}" alt="verify code"></div>
<div class="passport-captcha-input">
<input id="verify-code" type="text" placeholder="验证码">
</div>
</div>
<span id="btn-next" class="btn btn-next disable row">下一步</span>
</div>
</div>
... ...
... ... @@ -6,7 +6,17 @@
<span id="area-code" class="area-code">{{areaCode}}</span>
<input id="phone-num" class="input phone-num" type="text" placeholder="手机号">
</div>
<!-- 验证码: start-->
<div class="passport-captcha row">
<div class="passport-captcha-img">
<img class="passport-captcha-png" src="{{captchaUrl}}">
</div>
<div class="passport-captcha-input">
<input id="js-captcha" type="text" placeholder="验证码">
</div>
</div>
<!-- 验证码: end-->
<span id="btn-next" class="btn btn-next disable row">下一步</span>
<p class="register-tip">Yoho!Family账号可登录Yoho!Buy有货、Yoho!Now、mars及SHOW</p>
</div>
</div>
</div>
\ No newline at end of file
... ...
... ... @@ -15,5 +15,5 @@
<input type="hidden" name="area" id="area" value="{{area}}">
</div>
<script>
var canResend = {{canResend}};
var countdown = {{countdown}};
</script>
\ No newline at end of file
... ...
... ... @@ -7,6 +7,12 @@
<input id="phone-num" class="input phone-num" type="text" placeholder="手机号">
<button class="clear-input" type="button"></button>
</div>
<div class="passport-captcha row">
<div class="passport-captcha-img"><img src="{{captchaUrl}}" alt=""></div>
<div class="passport-captcha-input">
<input id="js-captcha" type="text" placeholder="验证码">
</div>
</div>
<button id="btn-next" class="btn btn-next disable row" disabled>获取短信验证码</button>
</div>
</div>
\ No newline at end of file
... ...
... ... @@ -12,7 +12,7 @@ const detailModel = require(`${mRoot}/detail`); // 商品详情 model
const introModel = require(`${mRoot}/intro`); // 商品尺码信息 model
const preferenceModel = require(`${mRoot}/preference`); // 商品偏好 model
const detailRelated = require(`${mRoot}/consult-comment`); // 商品评论咨询 model
const couponModel = require(`${mRoot}/coupon`); // 商品 优惠券 modal
const couponModel = require(`${mRoot}/coupon`); // 商品 优惠券 modal
const _ = require('lodash');
const helpers = global.yoho.helpers;
... ... @@ -139,12 +139,9 @@ exports.intro = (req, res, next) => {
exports.preference = (req, res, next) => {
preferenceModel({
productskn: req.query.productSkn,
yhchannel: req.yoho.channel,
brandId: req.query.brandId
limit: '20' // 后期值需要修改的话得手动改
}).then((result) => {
res.render('detail/preference', Object.assign({
layout: false
}, result));
res.send(result);
}).catch(next);
};
... ... @@ -161,6 +158,9 @@ exports.comments = (req, res, next) => {
});
detailRelated.comments(req.query).then((result) => {
if (result.navTitle) {
headerData.navTitle = result.navTitle;
}
res.render('detail/comments', Object.assign({
title: '购买评价',
pageHeader: headerData,
... ... @@ -182,6 +182,9 @@ exports.consults = (req, res, next) => {
});
detailRelated.consults(req.query, uid).then((result) => {
if (result.navTitle) {
headerData.navTitle = result.navTitle;
}
res.render('detail/consults', Object.assign({
title: '购买咨询',
pageHeader: headerData,
... ... @@ -248,7 +251,7 @@ exports.consultsubmit = (req, res, next) => {
data: ''
};
// 判断参数是否存在
// 判断参数是否存在
if (!req.body.product_id || !req.body.content) {
return res.json(data);
}
... ... @@ -344,7 +347,7 @@ exports.index = (req, res, next) => {
* @param {[type]} res [description]
* @return {[type]} [description]
*/
exports.indexData = (req, res, next)=> {
exports.indexData = (req, res, next) => {
if (!req.xhr) {
return next();
}
... ... @@ -361,7 +364,10 @@ exports.indexData = (req, res, next)=> {
ua: req.get('user-agent') || ''
}, req.__User__)).then((result) => {
if (_.isEmpty(result)) {
return res.json({code: 400, message: '数据错误'});
return res.json({
code: 400,
message: '数据错误'
});
}
result.studentPrice = req.__User__.isStudent && result && result.goodsPrice && result.goodsPrice.studentPrice ? result.goodsPrice.studentPrice : false;
return res.json(result);
... ...
... ... @@ -136,7 +136,7 @@ const _shop = (req, res, shopId) => {
_.forEach(result.hotList, (value, key) => {
result.hotList[key].tags = {};
result.hotList[key].is_soon_sold_out = false;
result.hotList[key].tags.isHot = true;
result.hotList[key].tags.is_hot = true;
});
// 有领券功能,不缓存
... ... @@ -222,7 +222,8 @@ const category = (req, res) => {
}),
goodList: params,
showDownloadApp: true,
pageFooter: true
pageFooter: true,
category: true
});
};
... ... @@ -489,6 +490,9 @@ const userCoupon = (req, res, next) => {
let isApp = req.body.app_version || req.body.appVersion || false;
let data = {};
cryptCouponId = parseInt(cryptCouponId, 10);
uid = parseInt(uid, 10);
if (uid) {
listModel.receiveCoupon(
uid,
... ...
... ... @@ -45,10 +45,15 @@ const selectNewSale = (req, res, next) => {
let params = _.assign({}, req.query);
newModel.getSearchData(params).then((result) => {
res.render('search/page', {
layout: false,
new: result
});
if (result.list.length > 0) {
res.render('search/page', {
layout: false,
new: result.list,
total: result.total
});
} else {
res.json(result);
}
}).catch(next);
};
... ...
... ... @@ -25,106 +25,109 @@ const list = (req, res, next) => {
let isQuerySecondClass = false; // 标识用户搜的是不是二级品类
let domain = null;
if (params.query) {
let activity = _.get(searchModel.searchKeyActivity(params.query), 'data.urlobj.appUrl', '');
if (activity) {
res.redirect(activity);
}
}
if (params.shop_id) {
params.shopId = params.shop_id;
}
/* 判断是不是品牌, 是品牌跳到品牌列表页(显示搜索框),判断是不是品类, 是品类加导航标题(不显示搜索框) */
Promise.all([
searchModel.getAllBrandNames(),
searchModel.getClassNames()
]).then(result => {
if (query) {
query = query.toLowerCase();
_.forEach(result[0], obj => {
if (query === obj.brandDomain) { // 精确查品牌域名
domain = query;
return false;
}
if (query === obj.brandName || query === obj.brandName || query === obj.brandName) { // 精确查品牌名称
domain = obj.brandDomain;
return false;
}
// if (obj.brandDomain.indexOf(query) > 0) { // 模糊查品牌域名
// domain = obj.brandDomain;
// return false;
// }
});
// 跳转到品牌商品列表页
if (domain !== null && !params.shop_id) {
let url = helpers.urlFormat('', {
from: 'search',
query: query
}, domain);
return res.redirect(url);
}
// 品类名称为空时跳出
if (!result[1]) {
return;
}
_.forEach(result[1].first, (obj) => {
// 精确查一级品类
if (obj === query) {
isQueryFirstClass = true;
return false;
}
});
_.forEach(result[1].second, (obj) => {
// 精确查二级品类
if (obj === query) {
isQuerySecondClass = true;
return false;
}
});
} else {
params.query = '';
}
// 搜索是一级品类
if (isQueryFirstClass) {
title = '全部' + query;
} else if (isQuerySecondClass) { // 搜索是二级品类
title = query;
} else { // 搜索其它内容
if (query || params.form) {
params.search = {
default: query === '' ? false : query,
url: helpers.urlFormat('', null, 'search')
};
if (params.query) {
return searchModel.searchKeyActivity(params.query).then(activityResult => {
let activity = _.get(activityResult, 'urlobj.appUrl', '');
if (activity) {
return res.redirect(activity);
} else {
/* 判断是不是品牌, 是品牌跳到品牌列表页(显示搜索框),判断是不是品类, 是品类加导航标题(不显示搜索框) */
return Promise.all([
searchModel.getAllBrandNames(),
searchModel.getClassNames()
]).then(result => {
if (query) {
query = query.toLowerCase();
_.forEach(result[0], obj => {
if (query === obj.brandDomain) { // 精确查品牌域名
domain = query;
return false;
}
if (query === obj.brandName || query === obj.brandName || query === obj.brandName) { // 精确查品牌名称
domain = obj.brandDomain;
return false;
}
// if (obj.brandDomain.indexOf(query) > 0) { // 模糊查品牌域名
// domain = obj.brandDomain;
// return false;
// }
});
// 跳转到品牌商品列表页
if (domain !== null && !params.shop_id) {
let url = helpers.urlFormat('', {
from: 'search',
query: query
}, domain);
return res.redirect(url);
}
// 品类名称为空时跳出
if (!result[1]) {
return;
}
_.forEach(result[1].first, (obj) => {
// 精确查一级品类
if (obj === query) {
isQueryFirstClass = true;
return false;
}
});
_.forEach(result[1].second, (obj) => {
// 精确查二级品类
if (obj === query) {
isQuerySecondClass = true;
return false;
}
});
} else {
params.query = '';
}
// 搜索是一级品类
if (isQueryFirstClass) {
title = '全部' + query;
} else if (isQuerySecondClass) { // 搜索是二级品类
title = query;
} else { // 搜索其它内容
if (query || params.form) {
params.search = {
default: query === '' ? false : query,
url: helpers.urlFormat('', null, 'search')
};
}
title = '搜索';
}
title = params.title ? params.title : title;
res.render('search/list', {
module: 'product',
page: 'search-list',
pageHeader: headerModel.setNav({
navTitle: title
}),
title: title,
goodList: params,
pageFooter: true
});
}).catch(next);
}
title = '搜索';
}
title = params.title ? params.title : title;
res.render('search/list', {
module: 'product',
page: 'search-list',
pageHeader: headerModel.setNav({
navTitle: title
}),
title: title,
goodList: params,
pageFooter: true
});
}).catch(next);
}
};
/**
... ... @@ -132,6 +135,7 @@ const list = (req, res, next) => {
*/
const index = (req, res, next) => {
let title = '搜索';
((render) => {
if (_.get(req, 'app.locals.wap.search.removeHotSearch', false)) {
render([]);
... ... @@ -182,10 +186,16 @@ const search = (req, res, next) => {
params.isApp = req.yoho.isApp;
searchModel.getSearchData(params).then((result) => {
res.render('search/page', {
layout: false,
new: result
});
if (result.list.length > 0) {
res.render('search/page', {
layout: false,
new: result.list,
total: result.total
});
} else {
res.json(result);
}
}).catch(next);
};
... ...
... ... @@ -147,7 +147,7 @@ let comments = (params) => {
if (result.comments && result.comments.length) {
if (result.commentsNum) {
_.set(data, 'pageHeader.navTitle', `购买评价(${result.commentsNum})`);
_.set(data, 'navTitle', `购买评价(${result.commentsNum})`);
}
data.comments = result.comments;
}
... ... @@ -174,7 +174,7 @@ let consults = (params, uid) => {
if (result[1].list && result[1].list.length) {
if (result[1].total) {
_.set(data, 'pageHeader.navTitle', `购买咨询(${result[1].total})`);
_.set(data, 'navTitle', `购买咨询(${result[1].total})`);
}
data.consults = result[1].list;
}
... ... @@ -218,9 +218,9 @@ let addConsult = (uid, productId, content) => {
module.exports = {
getCommentInfo, // 商品详情相关,获取评价,来自晒单
comments, // 商品详情相关-购买评价
consults, // 商品详情相关-购买咨询
addConsult, // 商品详情相关-添加咨询
comments, // 商品详情相关-购买评价
consults, // 商品详情相关-购买咨询
addConsult, // 商品详情相关-添加咨询
upvoteConsult, // 咨询点赞
getConsults // 获取咨询
};
... ...
... ... @@ -1250,8 +1250,8 @@ const _detailDataPkg = (origin, ua) => {
let extra = `?productSkn=${origin.product_skn}&brandId=${origin.brand_info.brand_id}`;
dest.preferenceUrl = `/product/detail/preference${extra}`;
dest.brandId = origin.brand_info.brand_id;
}
dest.brandId = origin.brand_id || 0;
dest.productSkn = origin.product_skn;
... ... @@ -1744,6 +1744,7 @@ let _detailDataPkgAsync = (origin, uid, vipLevel, ua) => {
}
let soldOut = (origin.storage_sum === 0) || (totalStorageNum === 0); // status
let notForSale = origin.attribute === 2;
let preSale = (origin.status === 0 && origin.advance_shelve_time > 0);
// 悬浮的购物车信息
dest.cartInfo = {
... ... @@ -1753,7 +1754,7 @@ let _detailDataPkgAsync = (origin, uid, vipLevel, ua) => {
};
// 显示加入购物车链接
if (!soldOut && !notForSale || origin.isLimitBuy) {
if (!soldOut && !notForSale && !preSale || origin.isLimitBuy) {
_.orderBy(colorGroup);
Object.assign(dest.cartInfo, {
productId: origin.product_id,
... ... @@ -1808,12 +1809,15 @@ let _detailDataPkgAsync = (origin, uid, vipLevel, ua) => {
origin.goods_id + '.html');
return callback();
}
} else if (notForSale) {
} else if (notForSale && !preSale) {
dest.cartInfo.notForSale = true;
return callback();
} else if (soldOut) {
} else if (soldOut && !preSale) {
dest.cartInfo.soldOut = true;
return callback();
} else if (preSale) {
dest.cartInfo.preSale = true;
return callback();
}
// 是否收藏 使用单独收藏接口获取
... ...
... ... @@ -515,6 +515,7 @@ const getShopData = (req, shopId, uid, isApp) => {
return Promise.all([
searchModel.getFilterSearchData({
shop_id: shopId,
type: 'default',//默认
brand: brandData.join(','),
order: '0',
channel: channel
... ...
... ... @@ -71,7 +71,15 @@ const getNewFocus = (channel) => {
const getSearchData = (params) => {
return _searchGoods(params).then((result) => {
if (result && result.code === 200) {
return productProcess.processProductList(result.data.product_list || [], {showTags: false});
let newList = {};
newList.list = productProcess.processProductList(result.data.product_list || [], {showTags: false});
if (parseInt(params.page) === 1) {
newList.total = result.data.total;
}
return newList;
} else {
logger.error('get product search api return code is not 200');
return [];
... ...
... ... @@ -48,18 +48,11 @@ const _formatProduct = (data) => {
};
module.exports = (data) => {
let finalResult = {};
return api.get('', {
method: 'h5.preference.Search',
productskn: data.productskn,
yhchannel: yhchannelMap[data.yhchannel],
brandId: data.brandId
method: 'app.product.preference',
product_skn: data.productskn,
limit: data.limit || '20'
}).then(result => {
if (result) {
finalResult.recommendList = _formatProduct(result);
}
return finalResult;
return result;
});
};
... ...
... ... @@ -91,7 +91,9 @@ const _searchGoods = (params) => {
delete params.filter_poolId;
}
if (params.brand) {
if (params.shop_id) {
method = 'app.search.li';
} else if (params.brand) {
method = 'app.search.brand';
}
... ... @@ -145,10 +147,18 @@ const _searchGoods = (params) => {
const getSearchData = (params) => {
return _searchGoods(params).then((result) => {
if (result && result.code === 200) {
return productProcess.processProductList(result.data.product_list || [], {
let newList = {};
newList.list = productProcess.processProductList(result.data.product_list || [], {
isApp: params.isApp || (params.appVersion && params.appVersion !== 'false'),
gender: _coverChannel[params.coverChannel]
});
if (parseInt(params.page) === 1) {
newList.total = result.data.total;
}
return newList;
} else {
logger.error('get product search api return code is not 200');
return [];
... ...
... ... @@ -140,6 +140,7 @@
<a id="soldOut" href="javascript:;" class="sold-out data-bind">已售罄</a>
<a id="notForSale" href="javascript:;" class="sold-out data-bind">非卖品</a>
<a id="limitNotForSale" href="javascript:;" class="sold-out limit data-bind">即将发售</a>
<a id="preSale" href="javascript:;" class="sold-out limit data-bind">即将开售</a>
<a href="javascript:;" id="addtoCart" class="addto-cart can-buy-limit data-bind">立即购买</a>
<a id="noLimitCode" href="javascript:;" class="sold-out limit data-bind">立即购买</a>
<input type="hidden" id="limitCodeUrl" name="limitCodeUrl" value="">
... ...
<div class="good-list-page yoho-page">
{{> search/list}}
{{#if category}}
<input type="text" id="category-point" style="display:none" value="{{category}}">
{{/if}}
</div>
... ...
<div class="total" data-id="{{total}}"></div>
{{# new}}
{{> common/goods}}
{{/ new}}
... ...
... ... @@ -121,9 +121,9 @@
<div class="discount-area first" id="navlist2">
<ul id="list-nav" class="home-sub-nav list-nav pos-list clearfix">
<li data-bp-id="shop_listnav_new_1" class="new active buriedpoint first-li-more">
<li data-bp-id="shop_listnav_default_1" class="default active buriedpoint first-li-more">
<a href="javascript:void(0);">
<span class="spanTest">最新</span>
<span class="spanTest">默认</span>
<span class="iconfont up cur hide">&#xe615;</span>
<span class="iconfont down cur">&#xe616;</span>
</a>
... ... @@ -191,9 +191,9 @@
</ul>
<div id="pos-list" class='hide'>
<ul class="home-sub-nav pos-list">
<li class="new active buriedpoint first-li-more" data-bp-id="shop_poslist_new_1">
<li class="default active buriedpoint first-li-more" data-bp-id="shop_listnav_default_1">
<a href="javascript:void(0);">
<span class="spanTest">最新</span>
<span class="spanTest">默认</span>
<span class="iconfont cur">&#xe616;</span>
<b></b>
</a>
... ... @@ -230,7 +230,6 @@
<ul>
<li class='active default' data-bp-id='shop_listnav_default_1'>默认</li>
<li class='new' data-bp-id='shop_listnav_new_1'>最新</li>
<li class='sale' data-bp-id='shop_listnav_sale_1'>销量</li>
</ul>
</div>
</div>
... ...
... ... @@ -92,9 +92,9 @@
<div>
<ul id="list-nav" class="list-nav clearfix">
<li class="new active buriedpoint first-li-more" data-bp-id="shop_listnav_new_1">
<li class="default active buriedpoint first-li-more" data-bp-id="shop_listnav_default_1">
<a href="javascript:void(0);">
<span class="nav-txt">最新</span>
<span class="nav-txt">默认</span>
<span class="iconfont up cur hide">&#xe615;</span>
<span class="iconfont down cur">&#xe616;</span>
</a>
... ...
'use strict';
const SECOND = 1;
... ... @@ -43,6 +42,7 @@ const cachePage = {
// 秒杀列表
'/product/seckill': 30 * SECOND,
'/product/seckill/list': 30 * SECOND,
// 秒杀详情
'/product/^\\/seckill\\/pro_([\\d]+)_([\\d]+)/': 30 * MINUTE,
... ... @@ -62,7 +62,19 @@ const cachePage = {
// 品牌一览
'/brands': 5 * MINUTE,
'/brands/search': 1 * MINUTE
'/brands/search': 1 * MINUTE,
// 直播活动
'/activity/live': 1 * MINUTE,
// 单品日
'/activity/single-day': 1 * MINUTE,
'/activity/single-day/getSingleData': 30 * SECOND,
'/activity/single-day/getProductData': 30 * SECOND,
// 店铺收藏
'/activity/shopCollect': 1 * MINUTE,
'/activity/shopNav': 30 * SECOND
};
... ...
... ... @@ -64,8 +64,9 @@ module.exports = {
},
loggers: {
infoFile: {
close: true,
name: 'info',
level: 'info',
level: 'error',
filename: 'logs/info.log',
maxFiles: 7
},
... ... @@ -78,12 +79,12 @@ module.exports = {
},
udp: { // send by udp
measurement: 'yohobuy_wap_node_log',
level: 'debug', // logger level
level: 'error', // logger level
host: 'influxdblog.web.yohoops.org', // influxdb host
port: '4444' // influxdb port
},
console: {
level: 'error',
level: 'debug',
colorize: 'all',
prettyPrint: true
}
... ...
... ... @@ -16,6 +16,11 @@ module.exports = () => {
req.url = `/activity${req.url}`;
}
if (/^\/shopping\/pay\/aliwapreturn/.test(req.url)) {
// 兼容php的url
req.url = `/cart${req.url}`;
}
if (/^\/sale/.test(req.url)) {
// sale 兼容php的url
res.redirect(301, helpers.urlFormat('/product/sale', req.query, 'default'));
... ...
... ... @@ -17,9 +17,9 @@
</li>
{{/data}}
</ul>
{{/if}}
<div class="swiper-pagination">
<div class="pagination-inner">
<div class="swiper-pagination">
<div class="pagination-inner">
</div>
</div>
</div>
{{/if}}
</div>
... ...
{{#data}}
<div style="background-image:url({{src}})" class="divide-image"></div>
{{/data}}
\ No newline at end of file
... ...
{{#data}}
<div class="hot-single">
{{> common/floor-header-more}}
{{> resources/new-floor-banner}}
<div class="hot-single-goods-list" {{#background}}style="background-image: url({{src}})"{{/background}}>
<ul>
{{#list}}
<li class="hot-single-goods">
<a href="//m.yohobuy.com/product/show_{{product_skn}}">
<img src="{{image default_images 153 206}}" alt="goods" class="goods-pic">
<div class="goods-info">
<h3 class="price">&yen; {{sales_price}}</h3>
<p class="view-num">{{view_num}}</p>
<p class="view-status">正在浏览</p>
</div>
</a>
</li>
{{/list}}
<!--<li class="hot-single-goods">
<img src="" alt="goods" class="goods-pic">
<div class="goods-info">
<h3 class="price">&yen; 188.00</h3>
<p class="view-num">22人</p>
<p class="view-status">已加入收藏</p>
</div>
</li>
<li class="hot-single-goods">
<img src="" alt="goods" class="goods-pic">
<div class="goods-info">
<h3 class="price">&yen; 188.00</h3>
<img src="" alt="little-head-icon" class="head-icon">
<p class="view-num view-margin">大大王</p>
<p class="view-status view-margin">10分钟前购买</p>
</div>
</li>
<li class="hot-single-goods">
<img src="" alt="goods" class="goods-pic">
<div class="goods-info">
<h3 class="price">&yen; 188.00</h3>
<p class="view-num">12人</p>
<p class="view-status">正在浏览</p>
</div>
</li>
<li class="hot-single-goods">
<img src="" alt="goods" class="goods-pic">
<div class="goods-info">
<h3 class="price">&yen; 188.00</h3>
<p class="view-num">22人</p>
<p class="view-status">已加入收藏</p>
</div>
</li>
<li class="hot-single-goods">
<img src="" alt="goods" class="goods-pic">
<div class="goods-info">
<h3 class="price">&yen; 188.00</h3>
<img src="" alt="little-head-icon" class="head-icon">
<p class="view-num view-margin">大大王</p>
<p class="view-status view-margin">10分钟前购买</p>
</div>
</li>-->
</ul>
</div>
</div>
{{/data}}
\ No newline at end of file
... ...
<div class="icons-wrapper">
{{#appIconList}}
<div class="icons-wrapper" style="background-image:url({{back_image}})">
<ul class="icons-list clearfix">
{{#data}}
<li class="icons-item item-{{../number}}"><a href="{{url}}" class="imagebar"><img src="{{image src 98 98}}" alt=""></a><a href="{{url}}" class="linkbar">{{title}}</a></li>
{{/data}}
</ul>
</div>
{{/appIconList}}
... ...
{{#data}}
<div class="new-first clearfix">
{{> common/floor-header-more}}
{{#list.[0]}}
<a href="{{url}}" class="float-container">
<img src="{{image src 268 360}}" alt="left" class="left" />
</a>
{{/list.[0]}}
{{#list.[1]}}
<a href="{{url}}" class="float-container">
<img src="{{image src 186 180}}" alt="right1" class="right" />
</a>
{{/list.[1]}}
{{#list.[2]}}
<a href="{{url}}" class="float-container">
<img src="{{image src 186 180}}" alt="right2" class="right" />
</a>
{{/list.[2]}}
{{#list.[3]}}
<a href="{{url}}" class="float-container">
<img src="{{image src 186 180}}" alt="right3" class="right" />
</a>
{{/list.[3]}}
{{#list.[4]}}
<a href="{{url}}" class="float-container">
<img src="{{image src 186 180}}" alt="right4" class="right" />
</a>
{{/list.[4]}}
</div>
{{/data}}
\ No newline at end of file
... ...
<div class="banner-center banner-center-swiper" style="border: 0;">
{{#if banner_image.[1]}}
<ul class="banner-list swiper-wrapper clearfix">
{{#banner_image}}
<li class="swiper-slide">
<a href="{{url}}">
<img src="{{image src 640 200}}" alt="">
</a>
</li>
{{/banner_image}}
</ul>
<div class="swiper-pagination">
<div class="pagination-inner">
</div>
</div>
{{else}}
{{#banner_image}}
<div class="banner-list">
<a href="{{url}}">
<img src="{{image src 640 200}}" alt="">
</a>
</div>
{{/banner_image}}
{{/if}}
</div>
\ No newline at end of file
... ...
{{#data}}
<div class="new-user-floor">
{{> common/floor-header-more}}
<div class="new-user-icon">新人专享</div>
{{> resources/new-floor-banner}}
<div class="new-user-goods-container" {{#background}} style="background-image: url({{src}})" {{/background}}>
<ul>
{{#list}}
<li class="new-user-good">
<a href="//m.yohobuy.com/product/show_{{product_skn}}">
<img src="{{image default_images 128 171}}" alt="goods-pic" class="goods-pic" />
<div class="goods-info">
<h3 class="title">{{product_name}}</h3>
<p class="price">&yen; {{sales_price}}</p>
<p class="buy-now">立即购买></p>
</div>
</a>
</li>
{{/list}}
</ul>
</div>
</div>
{{/data}}
\ No newline at end of file
... ...
{{#data}}
<div class="sale-floor clearfix">
{{> common/floor-header-more}}
{{> resources/new-floor-banner }}
{{#list.[0]}}
<a href="{{url}}" class="float-container time-floor">
<img src="{{image src 269 360}}" alt="sale-limit" class="sale-floor-limit">
<div class="sale-floor-time" data-time={{end_time}}>
<p class="limit-title"><i class="icon"></i>限时特卖</p>
<span class="hour">00</span>:
<span class="minute">00</span>:
<span class="second">00</span>
</div>
</a>
{{/list.[0]}}
{{#list.[1]}}
<a href="{{url}}" class="float-container">
<img src="{{image src 284 180}}" alt="sale-break" class="sale-floor-break">
</a>
{{/list.[1]}}
{{#list.[2]}}
<a href="{{url}}" class="sale-floor-entry">
<img src="{{image src 87 180}}" alt="sale-break" >
</a>
{{/list.[2]}}
{{#list.[3]}}
<a href="{{url}}" class="float-container">
<img src="{{image src 284 180}}" alt="sale-discount" class="sale-floor-discount">
</a>
{{/list.[3]}}
{{#list.[4]}}
<a href="{{url}}" class="sale-floor-entry">
<img src="{{image src 87 180}}" alt="sale-break" >
</a>
{{/list.[4]}}
</div>
{{/data}}
\ No newline at end of file
... ...
{{#data}}
<div class="shop-recom">
{{#if title}}
{{> common/floor-header-more}}
{{/if}}
<div class="shop-recom-container shop-recom-swiper-container">
<ul class="swiper-wrapper">
{{#list}}
<li class="swiper-slide recom-shop" shopId={{shopId}}>
<div class="fav-container fav-no">
<div class="shop-notfav"></div><span>收藏</span>
</div>
<div class="fav-container fav-yes" style="display:none">
<div class="shop-fav"></div><span>已收藏</span>
</div>
<span class="faved-num"></span>
<a href="{{url}}">
<img src="{{image src 640 208}}" alt="banner" class="top">
</a>
{{#goods0}}
<a href="{{url}}">
<img src="{{image src 320 146}}" alt="left" class="bottom">
</a>
{{/goods0}}
{{#goods1}}
<a href="{{url}}">
<img src="{{image src 320 146}}" alt="right" class="bottom">
</a>
{{/goods1}}
</li>
{{/list}}
</ul>
</div>
</div>
{{/data}}
\ No newline at end of file
... ...
{{#data}}
<div class="vip-only">
{{> common/floor-header-more}}
{{> resources/new-floor-banner}}
<div class="vip-only-goods-list" {{#background}} style="background-image: url({{src}})" {{/background}}>
<ul>
{{#list}}
<a href="//m.yohobuy.com/product/show_{{product_skn}}">
<li class="vip-only-goods">
<img src="{{image default_images 153 206}}" alt="goods" class="goods-pic">
<div class="goods-info">
<p class="vip-price vip1">&yen; {{vip1_price}}</p>
<p class="vip-price vip2">&yen; {{vip2_price}}</p>
<p class="vip-price vip3">&yen; {{vip3_price}}</p>
<p class="sale-price">&yen; {{market_price}} <span class="vip-icon"></span></p>
</div>
</li>
</a>
{{/list}}
</ul>
</div>
</div>
{{/data}}
\ No newline at end of file
... ...
{
"name": "m-yohobuy-node",
"version": "5.1.6",
"version": "5.1.10",
"private": true,
"description": "A New Yohobuy Project With Express",
"repository": {
... ... @@ -20,6 +20,7 @@
"dependencies": {
"bluebird": "^3.4.6",
"body-parser": "^1.15.2",
"captchapng": "0.0.1",
"cheerio": "^0.22.0",
"compression": "^1.6.2",
"connect-multiparty": "^2.0.0",
... ...

18.4 KB | W: | H:

26.5 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
... ... @@ -11,8 +11,7 @@ var $ = require('yoho-jquery'),
var bannerSwiper;
var C_ID,
getChannel;
var C_ID;
// 获取url中的参数
function getUrlParam(name) {
... ... @@ -182,21 +181,11 @@ $mask.on('click', function() {
});
// 埋点
getChannel = function functionName() {
var name = window.cookie('_Channel');
return {
boys: 1,
girls: 2,
kids: 3,
lifestyle: 4
}[name] || 1;
};
C_ID = getChannel();
C_ID = window._ChannelVary[window.cookie('_Channel')];
$('.floor-focus').find('li').on('click', function() {
event.preventDefault();
// event.preventDefault();
var foId = $(this).parents('.floor-focus').data('id'),
foName = $(this).parents('.floor-focus').data('floor-name'),
foindex = $(this).parents('.floor-focus').index() + 1,
... ...
... ... @@ -329,14 +329,30 @@ $('.close').on('click', function() {
$('.dialog').addClass('hidden');
$('.mask').addClass('hidden');
$('#dialog .content').html(' ');
$('body').css({
overflow: 'auto',
position: ''
});
});
$('.mask').on('touchmove', function() {
return false;
});
$('.coupon-description span').on('click', function() {
$('#message').removeClass('hidden');
$('.mask').removeClass('hidden');
$('body').css({
overflow: 'hidden',
position: 'fixed'
});
});
$('.description').on('click', function() {
$('#message').removeClass('hidden');
$('.mask').removeClass('hidden');
$('body').css({
overflow: 'hidden',
position: 'fixed'
});
});
$('.use-coupon-btn').on('click', function() {
... ...
... ... @@ -19,7 +19,7 @@ var singleDay = {
opt = {
$productList: $('.product-list'),
$swiper: $('.swiper-tab'),
getFlag: false,
getFlag: [],
previousScrollTop: 0,
winH: $(window).height(),
noResult: '<p class="no-result">未找到相关商品</p>',
... ... @@ -113,6 +113,7 @@ var singleDay = {
for (i; i < data[1].length; i++) {
self.$productList.append('<ul class="product-tab" data-page="0"></ul>');
self.getFlag[i] = false;
}
self.$productTab = $('.product-tab');
... ... @@ -126,10 +127,15 @@ var singleDay = {
$swiperTab.on('click', function() {
var index = $(this).index();
$('body').scrollTop(0);
$swiperTab.removeClass('active').eq(index).addClass('active');
if (self.$productTab.eq(index).find('li').length > 0) {
self.$productTab.hide().eq(index).fadeIn();
$('img.lazy').lazyload({
effect: 'fadeIn'
});
} else {
self.getProductData({
index: index,
... ... @@ -154,12 +160,12 @@ var singleDay = {
var page;
var curProductTab = self.$productTab.eq(params.index);
if (self.getFlag) {
if (self.getFlag[params.index]) {
return false;
}
page = +curProductTab.attr('data-page') + 1;
self.getFlag = true;
self.getFlag[params.index] = true;
loading.showLoadingMask();
$.ajax({
... ... @@ -175,15 +181,15 @@ var singleDay = {
curProductTab.find('.no-result').hide();
curProductTab.append(product(data));
curProductTab.attr('data-page', page);
self.getFlag = false;
self.getFlag[params.index] = false;
} else {
if (page === 1) {
if (curProductTab.find('.no-result').length === 0) {
curProductTab.append(self.noResult);
}
self.getFlag = false;
self.getFlag[params.index] = false;
} else {
self.getFlag = true;
self.getFlag[params.index] = true;
}
}
... ... @@ -199,7 +205,7 @@ var singleDay = {
error: function() {
tip.show('网络断开连接了~');
loading.hideLoadingMask();
self.getFlag = false;
self.getFlag[params.index] = false;
}
});
}
... ...
... ... @@ -155,7 +155,7 @@ var page = {
// 埋点
tracking: function() {
var C_ID = this.getChannel(),
UDID = window.queryString.udid || '',
UDID = window.queryString.udid || window.queryString.anbiudid || '',
SID = window.queryString.session_id || '';
// 刚进页面埋点
... ...
... ... @@ -22,7 +22,7 @@ var getChannel = function() {
// 抽奖埋点
var tracking = function() {
var C_ID = getChannel(),
UDID = window.queryString.udid || '',
UDID = window.queryString.udid || window.queryString.anbiudid || '',
SID = window.queryString.session_id || '';
setTimeout(function() {
... ...
... ... @@ -223,19 +223,11 @@ function updateConformButtonClassAndText() {
$('#chose-btn-sure').css('background-color', '#c0c0c0').html('已售罄');
} else if (limitProductCode || ticketsLimit) {
$('#chose-btn-sure').css('background-color', '#eb0313').html('立即购买');
} else if ($('.seckill-time').length >= 1) {
$('#chose-btn-sure').css('background-color', '#eb0313').html(isEdit ? '确认' : '立即购买');
} else {
$('#chose-btn-sure').css('background-color', '#eb0313').html(isEdit ? '确认' : '加入购物车');
}
if ($chosed.closest('.zero-stock').length === 2) {
$('#chose-btn-sure').css('background-color', '#c0c0c0').html('已售罄');
} else {
if ($('.seckill-time').length >= 1) {
$('#chose-btn-sure').css('background-color', '#eb0313').html(isEdit ? '确认' : '立即购买');
} else {
$('#chose-btn-sure').css('background-color', '#eb0313').html(isEdit ? '确认' : '加入购物车');
}
}
}
}
... ...
var $ = require('yoho-jquery'),
lazyLoad = require('yoho-jquery-lazyload');
require('../common');
lazyLoad($('img.lazy'));
function getGender() {
return window.cookie('_Channel') || 'boys';
}
require('../channel/maybe-like')(getGender());
if ($('#goods-list').length === 0) {
$('.maybe-like').hide();
}
... ...
... ... @@ -16,7 +16,7 @@ var $invoice = $('.invoice'),
$couponUse = $('.coupon-use.used'),
$addressWrap = $('.address-wrap'),
$coinCheck = $('.coin-check'),
$coinUsed = $('.coin .used'),
$coinLi = $('li.coin'),
$subBlock = $('.sub-block'),
$ticketsMobile = $('#mobile'),
payType,
... ... @@ -26,6 +26,7 @@ var $invoice = $('.invoice'),
dispatchInfo,
total,
activityId = $('#activity-id').val(),
isYohoCoinClick = $coinLi.data('yoho-coin-click') * 1, // 判断有货币是否可以单击
productSku = $('#product-sku').val();
var orderCont = window.cookie('order-info') && JSON.parse(window.cookie('order-info'));
... ... @@ -120,9 +121,13 @@ if (queryString.cartType || queryString.carttype || !orderInfo('cartType')) {
// $cur.addClass('chosed');
// }
$('.checkbox').on('touchstart', function() {
$('.checkbox').on('touchstart', function(e) {
var $this = $(this);
if ($(e.target).closest('.coin-check').length && !isYohoCoinClick) {
return true;
}
if ($this.hasClass('icon-cb-radio')) {
$this.removeClass('icon-cb-radio').addClass('icon-radio');
return;
... ... @@ -198,12 +203,14 @@ function orderCompute() {
if (typeof res.last_order_amount !== undefined) {
res.last_order_amount = (+res.last_order_amount).toFixed(2);
}
if (res.use_yoho_coin) {
$coinCheck.find('em').html('- ¥ ' + res.use_yoho_coin);
$coinUsed.html('已抵¥' + res.use_yoho_coin);
$coinCheck.find('em').show();
$coinUsed.show();
}
$coinLi.find('.msg').html(res.yohoCoinCompute.yohoCoinMsg);
isYohoCoinClick = res.yohoCoinCompute.yohoCoinClick * 1;
total = '';
if (res.promotion_formula_list) {
$.each(res.promotion_formula_list, function(index, value) {
... ... @@ -317,9 +324,29 @@ $('.dispatch-time').on('touchend', 'li', function() {
orderInfo('deliveryTimeId', $(this).data('id'));
});
$('.coin').on('touchend', function() {
$('.yoho-coin-help-dialog-bg, .yoho-coin-footer').on('touchend', function(e) {
e.preventDefault();
$('.yoho-coin-help-dialog-bg').addClass('hide');
$('.yoho-coin-help-dialog').addClass('hide');
});
$('.coin').on('touchend', function(e) {
var $this = $(this);
if ($(e.target).closest('.yoho-coin-help').length) {
$('.yoho-coin-help-dialog-bg').removeClass('hide');
$('.yoho-coin-help-dialog').removeClass('hide');
return true;
}
if ($(e.target).closest('.coin-check').length <= 0) {
return false;
}
if (!isYohoCoinClick) {
return true;
}
if ($this.find('.checkbox').hasClass('icon-cb-radio')) {
orderInfo('yohoCoin', $this.data('yoho-coin'));
$this.find('.can-use').hide();
... ... @@ -382,6 +409,11 @@ $('.dispatch').on('touchend', 'h3', function() {
});
$subBlock.on('touchstart', 'li', function() {
// 送货时间提示语li,不响应事件
if ($(this).hasClass('dispatch-time-info')) {
return true;
}
$.each($(this).parents('ul').find('i'), function() {
$(this).parents('ul').find('i').removeClass('icon-cb-radio').addClass('icon-radio');
});
... ... @@ -420,7 +452,7 @@ if (orderInfo('address') && orderInfo('address').is_support === 'N') {
}
// 校验手机号
$ticketsMobile.blur(function function_name(e) {
$ticketsMobile.blur(function function_name() {
var reg = /^[0123456789]{1,30}$/;
var mobile = $ticketsMobile.val();
... ...
... ... @@ -7,7 +7,8 @@ var $ = require('yoho-jquery'),
Swiper = require('yoho-swiper'),
lazyLoad = require('yoho-jquery-lazyload'),
fastclick = require('yoho-fastclick'),
noticeScroll = require('../plugin/notice-scroll');
noticeScroll = require('../plugin/notice-scroll'),
tip = require('../plugin/tip');
var $mobileWrap = $('.mobile-wrap'),
$overlay = $('.overlay'),
... ... @@ -18,6 +19,8 @@ var $mobileWrap = $('.mobile-wrap'),
swiperClass,
isen = true;
var C_ID;
require('../common');
fastclick.attach(document.body);
... ... @@ -227,4 +230,146 @@ window.setCookie('_Channel', $mobileWrap.data('channel'), {
domain: '.yohobuy.com'
});
// 店铺推荐滑动效果
var shopSwiper = new Swiper('.shop-recom-swiper-container', {
centeredSlides: true,
slidesPerView: 'auto',
paginationClickable: true,
slideActiveClass: 'recom-active',
});
// 店铺推荐人数和收藏初始查询
var checkShop = function() {
var shopIds = [];
$('.recom-shop').each(function() {
shopIds.push($(this).attr('shopId'));
});
$.ajax({
type: 'POST',
url: '/channel/shopRecom',
data: {
shopIds: shopIds.join(','),
},
}).then(function(result) {
if (result.code === 200) {
for (var i = 0, elem;
(elem = result.data[i]) != null; i++) {
var a = $('.recom-shop[shopId = ' + elem.id + ']');
a.find('.faved-num').text(elem.collectionNum + '人已收藏');
if (elem.favorite) {
a.find('.fav-no').hide();
a.find('.fav-yes').show();
}
}
}
});
};
checkShop();
// 店铺收藏 || 取消收藏
var $collect = $('.fav-container');
$collect.on('touchstart', function() {
var opt = $(this).hasClass('fav-yes') ? 'cancel' : 'ok';
var self = $(this);
$.ajax({
method: 'get',
url: location.protocol + '//m.yohobuy.com' + '/product/opt/favoriteBrand',
data: {
id: self.parent().attr('shopId'),
opt: opt,
type: 'shop',
},
xhrFields: {
withCredentials: true
},
success: function(data) {
var url = '';
if (data.code === 200) {
if (self.hasClass('fav-yes')) {
self.hide();
self.prev().show();
tip.show('取消收藏成功!');
} else {
self.hide();
self.next().show();
tip.show('收藏成功!');
}
}
if (data.code === 400) {
url = data.data;
location.href = url;
}
},
error: function() {
tip.show('网络断开连接了~');
searching = false;
}
});
});
// vip专属等级查询
$.ajax({
method: 'POST',
url: location.protocol + '//m.yohobuy.com' + '/channel/userVip',
data: {
channel: 1,
},
success: function(data) {
var vip = $('.vip-only');
if (data.code === 200 && Number(data.current_vip_level) !== 0) {
vip.show();
vip.find('.vip' + data.current_vip_level).show();
}
},
error: function() {
tip.show('网络断开连接了~');
searching = false;
}
});
// sale倒计时
var saleTime = function(elem, offsetTime) {
var hour = parseInt(offsetTime % (60 * 60 * 24) / (60 * 60), 10),
minute = parseInt(offsetTime % (60 * 60) / 60, 10),
second = offsetTime % 60;
if (offsetTime >= -1) {
$(elem).find('.hour').text(hour < 0 ? '00' : (hour < 10 ? ('0' + hour) : hour));
$(elem).find('.minute').text(minute < 0 ? '00' : (minute < 10 ? ('0' + minute) : minute));
$(elem).find('.second').text(second < 0 ? '00' : (second < 10 ? ('0' + second) : second));
if (offsetTime <= -1) { // 结束倒计时刷新状态
console.log('time done!');
} else {
setTimeout(function() {
saleTime(elem, --offsetTime);
}, 1000);
}
}
};
let endTime = $('.sale-floor-time').attr('data-time'),
// ~~两次取反位运算就是取整
limit = ~~((endTime * 1000 - Date.now()) / 1000);
saleTime('.sale-floor-time', limit);
require('./maybe-like')();
C_ID = window._ChannelVary[window.cookie('_Channel')];
$('.search-btn').click(function() {
if (window._yas && window._yas.sendCustomInfo) {
window._yas.sendCustomInfo({
op: 'YB_HOME_SEARCH_C',
param: JSON.stringify({
C_ID: C_ID,
})
}, true);
}
});
... ...
... ... @@ -14,20 +14,25 @@ var $footer = $('#yoho-footer'),
var RECID = (new Date().getTime() + '_H5_YOHOBUY_' + Math.floor(Math.random() * 1000000 + 1000000) +
'_' + Math.floor(Math.random() * 1000000 + 1000000));
var _ChannelVary = {boys: 1, girls: 2, kids: 3, lifestyle: 4};
var _ChannelVary = {
boys: 1,
girls: 2,
kids: 3,
lifestyle: 4
};
function cookie(name) {
var cookies = document.cookie,
cookieVal,
offset;
if (document.cookie && document.cookie !== '') {
offset = cookies.indexOf(name + '=');
if (offset > -1) {
offset += name.length + 1;
cookieVal = decodeURIComponent($.trim(cookies.substring(offset, cookies.indexOf(';', offset))));
}
cookieVal;
if (cookies) {
cookies = cookies.split(';');
cookies.forEach(function(c) {
if (c.indexOf(name) > -1) {
cookieVal = decodeURIComponent($.trim(c.replace(name + '=', '')));
return;
}
});
}
return cookieVal;
... ... @@ -204,7 +209,9 @@ $.extend({
// 单击下载按钮 - 接受微信商城或者第三方来源的数据埋点信息
if (queryString().union_type) {
setCookie('unionTypeYas', queryString().union_type, {path: '/'});
setCookie('unionTypeYas', queryString().union_type, {
path: '/'
});
}
}());
... ... @@ -229,7 +236,7 @@ $.extend({
uid = uid === 0 ? '' : uid;
window._ozuid = uid;// 暴露ozuid
window._ozuid = uid; // 暴露ozuid
if (window._yas) {
window._yas(1 * new Date(), '1.0.18', 'yohobuy_m', uid, '', '');
... ... @@ -323,7 +330,10 @@ function downLoadApp() {
if (window._yas && window._yas.sendCustomInfo) {
window._yas.sendCustomInfo({
op: 'YB_DOWNLOAD_C',
param: JSON.stringify({C_ID: _ChannelVary[cookie('_Channel')] || 1, TO_URL: appUrl})
param: JSON.stringify({
C_ID: _ChannelVary[cookie('_Channel')] || 1,
TO_URL: appUrl
})
}, true);
}
... ... @@ -369,6 +379,7 @@ function givePoint(parameter) {
(function() {
var channel = cookie('_Channel');
var header = $('#yoho-header, .homebuttom');
var footer = $('.footer-tab .tab-item.current');
if (!/^\/home/.test(location.pathname)) {
switch (channel) {
... ... @@ -398,6 +409,36 @@ function givePoint(parameter) {
}
break;
}
} else {
header.removeClass('girls', 'life-style', 'kids').addClass('boys');
}
switch (channel) {
case 'boys':
if (footer) {
footer.addClass('boys');
}
break;
case 'girls':
if (footer) {
footer.addClass('girls');
}
break;
case 'lifestyle':
if (footer) {
footer.addClass('life-style');
}
break;
case 'kids':
if (footer) {
footer.addClass('kids');
}
break;
default:
if (footer) {
footer.addClass('boys');
}
break;
}
}());
... ...
... ... @@ -154,7 +154,7 @@ function render(data) {
if (data.cartInfo.promotionId) {
$('.btn-minus,.btn-plus').find('span').addClass('disabled');
}
$('#limitNum').val(data.limit);
$('#limitNum').val(data.cartInfo.limit);
$('#promotionId').val(data.cartInfo.promotionId);
$('#single').val(data.single);
$('#chose-btn-sure').text(data.tickets ? '立即购买' : '加入购物车');
... ...
... ... @@ -4,8 +4,7 @@ var $ = require('yoho-jquery'),
loading = require('../plugin/loading'),
debounce = require('lodash/debounce');
var plusstar = {},
$footer = $('#yoho-footer');
var plusstar = {};
var windowHeight = $(window).height();
var scrollFn,
... ... @@ -186,6 +185,9 @@ plusstar = {
return true;
}
// 固定底部去除
window.rePosFooter();
// 记录切换tab位置
$(document).scrollTop(window.cookie(code) || 0);
... ... @@ -299,27 +301,21 @@ $(function() {
if (isApp) {
speckParamApp = {
udid: window.queryString.udid || '',
udid: window.queryString.udid || window.queryString.anbiudid || '',
apt: window.queryString.client_type || '',
sid: window.queryString.session_id || '',
};
}
// 男:1,女:2,潮童:3,创意生活:4
speckParamApp.CID = window.queryString.yh_channel || window._ChannelVary[window.cookie('_Channel')] || 1;
if (!isApp) {
$('.plusstar-resources').css({'margin-top': $('.tab-nav').height()});
} else {
$('.tab-nav').css({
position: 'relative'
});
$footer.css({
'max-width': '650px'
}).before(
'<div style="height: ' + parseInt($footer.css('height'), 0) + 'px"></div>'
);
}
// 男:1,女:2,潮童:3,创意生活:4
speckParamApp.CID = window.queryString.yh_channel || window._ChannelVary[window.cookie('_Channel')] || 1;
plusstar.init();
// 滚动翻页
... ...
... ... @@ -7,6 +7,7 @@
var $ = require('yoho-jquery');
var tip = require('../plugin/tip');
var checkCard = require('./bind-card-check');
var loading = require('../plugin/loading');
var applyButton = $('.open-btn');
var flag = true;
var formData = {
... ... @@ -34,6 +35,7 @@ var validateForm = function() {
};
require('../common');
require('./overdue-notice');
checkCard(formData);
... ... @@ -48,9 +50,6 @@ setInterval(function() {
}, 500);
applyButton.on('click', function() {
var self = this;
var ret = false;
if (!flag || $(this).hasClass('disabled') || !validateForm()) {
return false;
}
... ... @@ -60,13 +59,14 @@ applyButton.on('click', function() {
return false;
}
loading.showLoadingMask();
flag = false;
$.ajax({
type: 'GET',
url: '/home/installment/post-account',
data: formData,
async: false,
success: function(data) {
var params = {
action: 'go.bindCardResult',
... ... @@ -83,24 +83,35 @@ applyButton.on('click', function() {
if (data.code === 200) {
params.params.status = 1;
ret = true;
} else if (data.code === 500) {
tip.show('连接超时');
flag = true;
params.params.message = '网络连接超时!';
} else {
params.params.message = data.message;
ret = true;
}
url += encodeURIComponent(JSON.stringify(params));
$(self).attr('href', url);
loading.hideLoadingMask();
$('body').append('<a href=' + url + ' style="display: none;"><span class="jump">&npsb;</span></a>');
$('.jump').click();
},
error: function() {
loading.hideLoadingMask();
tip.show('网络断开连接了~');
flag = true;
}
});
});
return ret;
// 使用H5标签后 maxlength 标签失效
$('input[maxlength]').keyup(function() {
var value = $(this).val(),
length = $(this).attr('maxlength') || 20;
$(this).val(value.slice(0, length));
});
... ...
... ... @@ -7,20 +7,19 @@
var $ = require('yoho-jquery');
var tip = require('../plugin/tip');
var dialog = require('../plugin/dialog');
var yohoApp = require('../yoho-app');
var cardDetail = {
init: function() {
var self = this,
$relieveBtn = $('.relieve-btn'),
$changeBtn = $('.change-btn');
$changeBtn = $('.change-btn'),
asyncMode = yohoApp.isiOS;
self.asyncMode = asyncMode;
self.cardIdNo = $('.card-detail').data('cardId');
$('body').attr('ontouchstart', true);
if (window.queryString.setMaster) {
tip.show('切换成功!');
}
$relieveBtn.on('click', function() {
self.dialogAction({
text: '你确定要解除绑定此卡吗?解除绑定后该银行卡将不出现在还款银行卡列表中。',
... ... @@ -28,7 +27,13 @@ var cardDetail = {
errorText: '解除失败',
successAction: function() {
tip.show('解除成功!');
window.location.href = '/home/installment/bank-card?openby:yohobuy={"action":"go.relieveCardSuccess"}';
setTimeout(function() {
if (asyncMode) {
yohoApp.invokeMethod('go.relieveCardSuccess');
} else {
window.location.href = location.href + '&openby:yohobuy={"action":"go.relieveCardSuccess"}';
}
}, 1000);
}
});
});
... ... @@ -39,7 +44,14 @@ var cardDetail = {
url: '/home/installment/setMasterCard',
errorText: '切换失败',
successAction: function() {
window.location.href = '/home/installment/card-detail?cardIdNo=' + window.queryString.cardIdNo + '&setMaster=true';
tip.show('切换成功!');
setTimeout(function() {
if (asyncMode) {
yohoApp.invokeMethod('go.instalmentMyCardList');
} else {
window.location.href = location.href + '&openby:yohobuy={"action":"go.instalmentMyCardList"}';
}
}, 1000);
}
});
});
... ...
... ... @@ -23,10 +23,12 @@ window.reMarginFooter('.footer-tab');
// 部分老用户没有头像,显示默认头像
avatar = $userAvatar.data('avatar');
myImage.src = avatar;
myImage.onload = function() {
$userAvatar.css('background-image', 'url(' + avatar + ')');
};
if (avatar) {
myImage.src = avatar;
myImage.onload = function() {
$userAvatar.css('background-image', 'url(' + avatar + ')');
};
}
noticeScroll('.notice', $('.notice').data('time') * 1000);
... ... @@ -36,4 +38,3 @@ $('.yoho-page').on('touchstart', '.list-item, .type-item, .order-title', functio
}).on('touchend touchcancel', '.list-item, .type-item, .order-title', function() {
$(this).removeClass('highlight');
});
... ...
... ... @@ -7,10 +7,10 @@
var $ = require('yoho-jquery'),
ellipsis = require('yoho-mlellipsis'),
cookie = require('yoho-cookie'),
Swiper = require('yoho-swiper'),
ListData = require('./installment-goods'),
bp = require('./burying-point'),
PullRefresh = require('../plugin/pull-refresh'),
noticeScroll = require('../plugin/notice-scroll'),
uuid = require('uuid');
var installment = {
... ... @@ -20,7 +20,6 @@ var installment = {
self.paramsInit();
$(window).on('mousewheel', false);
noticeScroll('.notice', $('.notice').data('time') * 1000);
ellipsis.init();
self.setDetailText();
... ... @@ -49,6 +48,7 @@ var installment = {
self.$tab.eq(0).addClass('on').siblings().removeClass('on');
self.$installmentCont.hide().eq(0).fadeIn();
}
self.noticeScroll('.notice', $('.notice').data('time') * 1000);
cookie.remove('installmentTab');
... ... @@ -93,6 +93,15 @@ var installment = {
self.setCookies();
},
noticeScroll: function(selecter, time) {
new Swiper(selecter, {
autoplay: time,
direction: 'vertical',
speed: 500,
loop: true,
noSwiping: true
});
},
setDetailText: function() { // 标题限制行数
var $this, $title;
... ... @@ -166,6 +175,7 @@ var installment = {
window.setCookie('yhChannel', window.queryString.yh_channel);
window.setCookie('udid', window.queryString.udid);
window.setCookie('clientType', window.queryString.client_type);
window.setCookie('appVersion', window.queryString.app_version);
}
};
... ...
... ... @@ -338,3 +338,8 @@ $reaMask.on('touchend', function(event) {
$reaMask.css('visibility', 'hidden');
event.stopPropagation();
});
$('.nav-tap').on('click', function(e){
var $cur = $(e.target);
location.replace($cur.data('url'));
})
\ No newline at end of file
... ...
... ... @@ -20,5 +20,8 @@ $('.installment-starting-service-page .notice').on('click', function() {
return false;
});
$('.add-account-page .notice').on('click', function() {
$notice.show();
});
$('body').attr('ontouchstart', true);
... ...
... ... @@ -9,6 +9,8 @@ var $ = require('yoho-jquery');
var $phoneNum = $('#phone-num'),
$countrySelect = $('#country-select'),
$areaCode = $('#area-code'),
$verifyCode = $('#verify-code'),
$verifyCodeImg = $('#verify-code-img'),
$btnNext = $('#btn-next');
var api = require('../api');
... ... @@ -33,25 +35,37 @@ $countrySelect.change(function() {
$areaCode.text($countrySelect.val());
});
$verifyCodeImg.on('touchstart', function() {
var oldSrc = $verifyCodeImg.attr('src').split('=');
$verifyCodeImg.attr('src', oldSrc[0] + '=' + Date.now());
$verifyCode.val('');
});
$btnNext.on('touchstart', function() {
var pn = trim($phoneNum.val()),
area = trim($countrySelect.val());
area = trim($countrySelect.val()),
verify = trim($verifyCode.val());
if ($btnNext.hasClass('disable')) {
return;
}
if (area && pn && api.phoneRegx[area].test(pn)) {
if (verify && area && pn && api.phoneRegx[area].test(pn)) {
$.ajax({
url: '/passport/back/sendcode',
type: 'POST',
data: {
areaCode: area.replace('+', ''),
phoneNum: pn
phoneNum: pn,
verifyCode: verify
},
success: function(data) {
if (data.code === 200) {
location.href = data.data;
} else if (data.code === 409) {
showErrTip(data.message);
location.href = data.refer;
} else {
showErrTip(data.message);
}
... ... @@ -59,6 +73,8 @@ $btnNext.on('touchstart', function() {
});
} else if (!area) {
showErrTip('出错了,请重新刷新页面');
} else if (!verify) {
showErrTip('请输入验证码');
} else {
showErrTip('手机号格式不正确,请重新输入');
}
... ...
... ... @@ -16,7 +16,6 @@ var validatePWD = require('../password-check');
var trim = $.trim;
var showErrTip = tip.show;
var qs;
require('../../common');
... ... @@ -44,7 +43,7 @@ if (qs.selected && qs.selected === 'N') {
$('.pitch').removeClass('select').html('&#xe647;');
}
if(qs.pwd) {
if (qs.pwd) {
$pwd.val(qs.pwd);
if (trim($pwd.val()) === '') {
... ... @@ -64,6 +63,41 @@ $('.pitch').on('click', function() {
}
});
function setPassword() {
return $.ajax({
type: 'POST',
url: '/passport/reg/setpassword',
data: {
password: trim($pwd.val()),
phoneNum: $('#phone-num').val(),
areaCode: $('#area-code').val(),
smsCode: $('#sms-code').val(),
token: $('#token').val()
},
success: function(data) {
var res = data.data;
if (data.code === 200) {
showErrTip('注册成功');
// 统计代码:用于统计从哪个渠道注册成功的
if (window._yas && window._yas.sendCustomInfo) {
window._yas.sendCustomInfo({
op: 'YB_REGISTER_SUCCESS_L',
param: JSON.stringify({
C_ID: window._ChannelVary[window.cookie('_Channel')] || 1,
UNION_TYPE: window.queryString.union_type || window.cookie('unionTypeYas') || false
})
}, true);
}
location.href = res.href;
} else {
showErrTip(data.message);
}
}
});
}
$btnSure.on('touchstart', function() {
var pwd = trim($pwd.val());
... ... @@ -74,30 +108,8 @@ $btnSure.on('touchstart', function() {
if (!validatePWD(pwd)) {
showErrTip('密码6-20位,请重新输入');
} else {
if ($('.pitch').hasClass('select')) {
$.ajax({
type: 'POST',
url: '/passport/reg/setpassword',
data: {
password: pwd,
phoneNum: $('#phone-num').val(),
areaCode: $('#area-code').val(),
smsCode: $('#sms-code').val(),
token: $('#token').val()
},
success: function(data) {
var res = data.data;
if (data.code === 200) {
showErrTip('注册成功');
location.href = res.href;
} else {
showErrTip(data.message);
}
}
});
setPassword();
} else {
$('.prompt').show();
... ... @@ -106,27 +118,7 @@ $btnSure.on('touchstart', function() {
$('.pitch').addClass('select');
$('.pitch').html('&#xe60a;');
$.ajax({
type: 'POST',
url: '/passport/reg/setpassword',
data: {
password: pwd,
phoneNum: $('#phone-num').val(),
areaCode: $('#area-code').val(),
token: $('#token').val()
},
success: function(data) {
var res = data.data;
if (data.code === 200) {
showErrTip('注册成功');
location.href = res.href;
} else {
showErrTip(data.message);
}
}
});
setPassword();
});
$('.deny').on('click', function() {
... ...
... ... @@ -8,6 +8,8 @@ var $ = require('yoho-jquery');
var $phoneNum = $('#phone-num'),
$countrySelect = $('#country-select'),
$areaCode = $('#area-code'),
$captcha = $('#js-captcha'),
$captchaPNG = $('.passport-captcha-png'),
$btnNext = $('#btn-next');
var api = require('../api');
... ... @@ -22,13 +24,44 @@ api.selectCssHack($('#country-select'));
api.bindClearEvt();
$phoneNum.bind('input', function() {
if (trim($phoneNum.val()) === '') {
$btnNext.addClass('disable');
} else {
$btnNext.removeClass('disable');
}
});
/**
* 必填校验
*/
function checkEnableNext() {
var phone = trim($phoneNum.val());
var area = trim($countrySelect.val());
var captcha = trim($captcha.val());
var ret = true;
$.each([phone, area, captcha], function(i, val) {
if (!val) {
ret = false;
return ret;
}
});
return ret;
}
/**
* 刷新 校验码
*/
function refreshCaptcha() {
$captcha.val('').focus();
$captchaPNG.attr('src', ['//m.yohobuy.com/passport/reg/captcha.png', '?t=', Date.now()].join(''));
}
/*
Event bind
*/
$('.reg-page')
.on('input', '.phone-num, #js-captcha', function() {
$btnNext.toggleClass('disable', !checkEnableNext());
})
.on('click', '.passport-captcha-png', refreshCaptcha);
$countrySelect.change(function() {
$areaCode.text($countrySelect.val());
... ... @@ -36,7 +69,13 @@ $countrySelect.change(function() {
$btnNext.on('touchstart', function() {
var pn = trim($phoneNum.val()),
areaCode = $countrySelect.val();
areaCode = $countrySelect.val(),
captcha = $captcha.val().trim();
if (!captcha) {
tip.show('请输入验证码');
return false;
}
if ($btnNext.hasClass('disable')) {
return;
... ... @@ -56,18 +95,22 @@ $btnNext.on('touchstart', function() {
type: 'POST',
data: {
areaCode: areaCode.replace('+', ''),
phoneNum: pn
phoneNum: pn,
captcha: captcha
},
success: function(data) {
if (data.code === 200) {
location.href = data.data;
} else {
refreshCaptcha();
showErrTip(data.message);
requested = false;
}
},
error: function() {
showErrTip('出错了,请重试');
refreshCaptcha();
requested = false;
}
});
... ...
... ... @@ -22,8 +22,8 @@ page = {
init: function() {
this.domInit();
this.bindEvents();
if (!window.canResend) {
this.countDown();
if (window.countdown > 0) {
this.countDown(window.countdown);
}
},
... ... @@ -72,11 +72,14 @@ page = {
});
},
countDown: function() {
countDown: function(during) {
var self = this;
var second = this.time;
if (this.timerId) {
if (during) {
clearInterval(this.timerId);
second = during;
} else if (this.timerId) {
return;
}
... ... @@ -116,6 +119,8 @@ page = {
if (res.code === 200) {
self.countDown();
return;
} else {
res.during && (self.countDown(res.during));
}
tip.show(res.message);
... ...
... ... @@ -6,7 +6,10 @@ var $countrySelect,
$areaCode,
$nextBtn,
$resetBtn,
$captcha,
$captchaPNG,
$phoneNum;
var page;
require('js/common');
... ... @@ -25,6 +28,8 @@ page = {
$nextBtn = $('#btn-next');
$phoneNum = $('#phone-num');
$resetBtn = $('.clear-input');
$captcha = $('.passport-captcha input');
$captchaPNG = $('.passport-captcha-img img');
},
bindEvent: function() {
var self = this;
... ... @@ -36,6 +41,12 @@ page = {
self.toggleNextBtn();
});
$captcha.on('input', function() {
self.toggleNextBtn();
});
$captchaPNG.on('click', $.proxy(this.refreshCapatch, this));
$nextBtn.on('click', function() {
self.goNext();
});
... ... @@ -51,7 +62,7 @@ page = {
// 切换$nextBtn disable状态
toggleNextBtn: function() {
var bool = Boolean($.trim($phoneNum.val()));
var bool = Boolean($.trim($phoneNum.val())) && Boolean($.trim($captcha.val()));
$nextBtn
.toggleClass('disable', !bool)
... ... @@ -60,10 +71,17 @@ page = {
$resetBtn.toggle(bool);
},
refreshCapatch: function() {
$captchaPNG.attr('src', '/passport/sms_login/captcha.png?t=' + Date.now());
$captcha.val('');
},
// 提交按钮
goNext: function() {
var self = this;
var areaCode = $countrySelect.val();
var phone = $.trim($phoneNum.val());
var captcha = $.trim($captcha.val());
if ($nextBtn.prop('disabled')) {
return;
... ... @@ -77,7 +95,8 @@ page = {
$nextBtn.prop('disabled', true);
$.get('/passport/sms_login/token.json', {
area: areaCode.replace('+', ''),
mobile: phone
mobile: phone,
captcha: captcha
})
.done(function(data) {
if (data.code === 200) {
... ... @@ -85,6 +104,7 @@ page = {
$nextBtn.off();
location.href = data.redirect;
} else {
self.refreshCapatch();
tip.show(data.message);
}
})
... ...
... ... @@ -86,8 +86,8 @@ var brandCoupon = {
}, 1000);
}
}
}).fail(function(res) {
tip.show(res.message);
}).fail(function() {
tip.show('网络异常,请稍后再试');
});
},
... ...
... ... @@ -18,8 +18,6 @@ var navtabEle = document.getElementById('nav-tab'),
readmore = document.getElementById('readmore'),
readmoreHammer = readmore && new Hammer(readmore);
(function() {
consultsNum = $('#nav-tab .consults-num').html() - 0;
... ... @@ -77,14 +75,14 @@ if (navtabHammer) {
if (gotoConsultHammer) {
gotoConsultHammer.on('tap', function() {
var link = $(gotoConsultEle).find('a').attr('href');
link += (link.indexOf('?') >=0 ? '&' : '?') + 'from=' + encodeURIComponent(location.href);
link += (link.indexOf('?') >= 0 ? '&' : '?') + 'from=' + encodeURIComponent(location.href);
location.href = link;
});
}
// 咨询页面固定header
if ($('.goods-consults-page').length > 0) {
$('#yoho-header').css('position', 'fixed').css('top', '0');
// $('#yoho-header').css('position', 'fixed').css('top', '0');
}
if ($('.goods-consults-page').length > 0) {
... ...
... ... @@ -105,6 +105,26 @@ function search() {
searching = false;
end = true;
loading.hideLoadingMask();
// 视频埋点
$('video').on('play', function() {
var _channel = cookie('_Channel');
var cid = {
boys: 1,
girls: 2,
kids: 3,
lifestyle: 4
}[(_channel ? _channel : 'boys')];
var pid = $('#productId').val();
window._yas.sendCustomInfo({
op: 'YB_GDS_DT_VIDEO_C',
param: JSON.stringify({
C_ID: cid,
PRD_ID: pid,
}),
}, true);
});
},
error: function() {
tip.show('网络断开连接了~');
... ...
... ... @@ -14,18 +14,45 @@ var productId = $('#productId').val();
var skn = $('#productSkn').val(),
productCode = $('#limitProductCode').val();
var C_ID = window._ChannelVary[window.cookie('_Channel')],
PRD_ID;
$('#likeBtn').on('touchstart', function() {
var opt,
favorite;
var $this = $(this);
PRD_ID = productId;
if ($this.hasClass('liked')) {
opt = 'cancel';
favorite = 0;
if (window._yas && window._yas.sendCustomInfo) {
window._yas.sendCustomInfo({
op: 'YB_COLLECTION_C',
param: JSON.stringify({
C_ID: C_ID,
PRD_ID: PRD_ID,
COL_TYPE: 2
})
}, true);
}
} else {
opt = 'ok';
favorite = 1;
if (window._yas && window._yas.sendCustomInfo) {
window._yas.sendCustomInfo({
op: 'YB_COLLECTION_C',
param: JSON.stringify({
C_ID: C_ID,
PRD_ID: PRD_ID,
COL_TYPE: 1
})
}, true);
}
}
$.ajax({
... ...