Authored by zzzzzzz

合并master

Showing 100 changed files with 1419 additions and 155 deletions

Too many changes to show.

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

... ... @@ -7,11 +7,6 @@
const config = require('./config/common');
// use one apm
if (config.useOneapm) {
require('oneapm');
}
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
... ...
... ... @@ -33,12 +33,14 @@ exports.main = (req, res, next) => {
res.locals.liveRoom = id;
res.locals.module = 'activity';
res.locals.page = 'live-play';
res.locals.enableFoot = Number(req.query.no) !== 1;
model.fetchInfo(id, isReplay)
.then(result => {
if (!result.data) {
return next();
}
res.render('live/play', result.data);
})
.catch(next);
... ...
/**
* 市场推广
* <jing.li@yoho.cn>
* 2016/09/07
*/
'use strict';
const indexModel = require('../models/market');
exports.index = (req, res, next) => {
indexModel.index({
}).then((result) => {
res.render('market/market', Object.assign(result, {
title: 'Yoho!Buy 有货'
}));
}).catch(next);
};
... ...
... ... @@ -354,7 +354,7 @@ exports.verifystudent = (req, res, next) => {
}
} else {
if (datas[2].code === 500) {
prompt = '芝麻信用认证失败,稍后重试!';
prompt = '请重新认证!';
} else {
prompt = datas[2].message;
}
... ...
/**
* 市场推广
* <jing.li@yoho.cn>
* 2016/09/07
*/
'use strict';
const service = global.yoho.ServiceAPI;
const helpers = global.yoho.helpers;
const _ = require('lodash');
const _indexBoys = () => {
return service.get('/operations/api/v5/resource/home', {
content_code: '797c299afc4170452cf7b2048806b6b8',
gender: 1,
limit: 1000,
page: 1
});
};
const _index = () => {
return service.get('/operations/api/v5/resource/home', {
content_code: '8512bf0755cc549ac323f852c9fd945d',
gender: 1,
limit: 1000,
page: 1
});
};
const index = () => {
return service.all([
_indexBoys(),
_index()
]).then(result => {
let resu = {
swiper: [],
floorAdList: [],
newsList: [],
download: []
};
if (result[0].data.list[0] && result[0].data) {
let headerTip = result[0].data.list[0].data.text;
resu = Object.assign(resu, { headerTip });
}
if (result[1].data.list[0].data && result[1].data) {
let adList = result[1].data.list[0].data;
let build = [];
adList.forEach(ad => {
build.push({
img: helpers.image(ad.src, 640, 310),
url: ad.url
});
});
resu.swiper = build;
}
if (result[0].data.list[1] && result[0].data) {
let floorList = result[0].data.list[1].data.list;
let floorAdListTitle = result[0].data.list[1].data.title.title;
resu = _.assign(resu, { floorAdListTitle });
let floor = [];
let i = 0;
floorList.forEach(ad => {
if (i < 12) { // 控制显示条数,默认1-12
floor.push({
img: helpers.image(ad.src, 640, 170),
url: ad.url,
title: ad.title
});
i++;
}
});
resu.floorAdList = floor;
}
if (result[0].data.list[2] && result[0].data) {
let newsList = result[0].data.list[2].data.list[0];
let news = [{
img: helpers.image(newsList.src, 640, 370),
url: newsList.url,
title: newsList.title,
alt: newsList.alt
}];
resu.newsList = news;
}
if (result[0].data.list[3] && result[0].data) {
let downlist = result[0].data.list[3].data[0];
let down = [{
img: helpers.image(downlist.src, 640, 275),
url: downlist.url,
alt: downlist.alt
}];
resu.download = down;
}
return resu;
});
};
module.exports = {
index
};
... ...
... ... @@ -15,6 +15,7 @@ const student = require(`${cRoot}/student`);
const live = require(`${cRoot}/live`);
const invite = require(`${cRoot}/invite`);
const vipDay = require(`${cRoot}/vipDay`);
const market = require(`${cRoot}/market`);
// routers
... ... @@ -51,6 +52,8 @@ router.get('/live/:id', live.main);
router.get('/invite', invite.index);
router.get('/invite/index', invite.index);
router.get('/market', market.index);// 市场推广活动
router.get(/\/invite\/share_([\d]+)_([\d]+)_([\d]+).html/, invite.share);
router.get('/invite/sendRegCodeToMobile', invite.sendRegCodeToMobile);
router.get('/invite/checkOldUserCoupon', invite.checkOldUserCoupon);
... ...
... ... @@ -10,10 +10,11 @@
<section class='s-text'>
<h6>权益1:新品立享9折</h6>
<p>1、学生购买原价新品时,可立即享受9折优惠,与VIP折扣不可同时享受。</p>
<h6>权益2:每满100返100有货币</h6>
<p>1、学生购买商品时,商品金额每满100元即可获得100有货币;</p>
<p>2、有货币有效期:获得当日至次年12月31日,逾期自动作废;</p>
<p>3、查看有货币:登录后,点击“个人中心”在“我的有货币”中可以查看有货币余额及明细</p>
<h6>权益2:每1元返1个有货币</h6>
<p>1、学生购买商品时,以商品的实际成交金额计算,每1元返1个有货币;</p>
<p>2、返有货币时间:确认收货7日后,系统将自动将对应数量的有货币返至购买账户;</p>
<p>3、有货币有效期:获得当日至次年12月31日,逾期自动作废;</p>
<p>4、查看有货币:登录后,点击“个人中心”在“我的有货币”中可以查看有货币余额及明细。</p>
<h6>权益3:免单抽奖</h6>
<p>1、每月将在累计购物金额最高的学校中,抽取3名幸运学生用户,获得免单资格;</p>
<p>2、免单用户名单将在每月第1个工作日公布在有货微信公众号上,可关注【有货YOHOBUY】;</p>
... ...
... ... @@ -13,6 +13,9 @@
<p>加载中</p>
</div>
<div class="live-loading-cover" style="background-image: url('{{pic}}');"></div>
<a href="javascript: history.back();" class="live-btn-close">
<i class="iconfont">&#xe623</i>
</a>
</div>
<div id="live_touch_layer"></div>
... ... @@ -65,9 +68,6 @@
<a href="javascript:;" class="live-btn-share">
<i class="iconfont">&#xe600</i>
</a>
<a href="javascript: history.back();" class="live-btn-close">
<i class="iconfont">&#xe623</i>
</a>
</section>
</div>
{{/canPlay}}
... ... @@ -122,6 +122,7 @@
{{/notBegin}}
{{! footer}}
{{#enableFoot}}
<div class="float-layer" id="float-layer-app">
<div class="float-layer-left">
<span class="yoho-icon iconfont">&#xe60d;</span>
... ... @@ -135,6 +136,7 @@
立即下载
</a>
</div>
{{/enableFoot}}
</div>
<script>
var live_start_time = {{live_start_time}};//该直播开始时间
... ... @@ -142,7 +144,6 @@
var live_room = {{liveRoom}};//房间id,资讯id
var replay_total_likes = {{like_num}};//重播总计点赞数,取的是直播最终点赞数
var replay_user_nums = {{audience_num}};//重播观看人数,取的是直播时最终观看人数
var site_url = '';
var site_domain = 'http://api.live.yoho.cn/';
// share data
... ...
<div class="ma-container">
<div class="ma-header">
<div>{{headerTip}}</div>
</div>
<div class="tab">
<div class="swiper-container">
<div class="swiper-wrapper">
{{# swiper}}
<div class="swiper-slide">
<a href="{{url}}">
<img class="swiper-lazy" data-src="{{img}}">
</a>
</div>
{{/ swiper}}
</div>
<div class="swiper-pagination"></div>
</div>
</div>
{{# floorAdListTitle}}
<div class="floor-top">
<img src="{{imgSrc '//cdn.yoho.cn/m-yohobuy-node/assets/img/activity/market/floor-top-1.jpg'}}" />
</div>
{{/ floorAdListTitle}}
<ul class="floor-ul">
{{# floorAdList}}
<a href="{{url}}">
<li>
<img src="{{img}}" />
<p>{{title}}</p>
</li>
</a>
{{/ floorAdList}}
</ul>
{{# newsList}}
<div class="floor-top">
<img src="{{imgSrc '//cdn.yoho.cn/m-yohobuy-node/assets/img/activity/market/floor-top-2.jpg'}}" />
</div>
<div class="floor-c">
<a href="{{url}}">
<img src="{{img}}" alt="{{alt}}" />
</a>
<p>{{title}}</p>
</div>
{{/ newsList}}
{{# download}}
<a href="{{url}}" class="down">
<img src="{{img}}" alt="{{alt}}" />
</a>
{{/ download}}
</div>
\ No newline at end of file
... ...
... ... @@ -87,7 +87,7 @@
<h1>学生专属活动</h1>
{{#each data.list}}
<a class='s-activity' href="{{url}}">
<img src='{{image src 750 234}}' title='{{title}}'>
<img src='{{image src 640 200}}' title='{{title}}'>
</a>
{{/each}}
</section>
... ...
{{#unless isApp}}
<header class="yoho-header">
<a href="javascript:history.go(-1);" class="iconfont nav-back"></a>
<a href="//m.yohobuy.com/activity/student?openby:yohobuy={'action':'go.h5','params':{'islogin':'N','url':'{{http}}//m.yohobuy.com/activity/student'}}" class="iconfont nav-back"></a>
<p class="nav-title">学生身份认证</p>
</header>
{{/unless}}
... ...
... ... @@ -134,6 +134,11 @@ const _getChannelResource = (params) => {
cache: true
}).then(result => {
if (result && result.code === 200) {
for (let item of result.data.list) {
item.template_name === 'single_image' &&
item.data.length === 1 &&
(item.singleOne = true);
}
return resourcesProcess(result.data.list);
} else {
logger.error('index resouce is not 200');
... ...
/**
* 逛列表页 controller
* @author: jing.li@yoho.cn<jing.li@yoho.cn>
* @date: 2016/09/05
*/
'use strict';
const headerModel = require('../../../doraemon/models/header'); // 头部model
const indexModel = require('../models/index');
/**
* 逛列表页
* @param req
* @param res
* @param next
*/
exports.index = (req, res, next) => {
let headerData = headerModel.setNav({
navTitle: '逛'
});
let responseData = {
pageHeader: headerData,
module: 'guang',
page: 'index',
title: '逛',
pageFooter: true
};
let param = {
uid: req.user.uid || 6228593,
udid: req.user.udid,
type: req.query.type || 0,
gender: req.query.gender || '1,3'
};
indexModel.getArticle(param).then(result => {
res.render('index', Object.assign(responseData, result));
}).catch(next);
};
... ...
... ... @@ -23,7 +23,7 @@ app.engine('.hbs', hbs({
extname: '.hbs',
defaultLayout: 'layout',
layoutsDir: doraemon,
partialsDir: [path.join(__dirname, 'views/partial'), `${doraemon}/partial`],
partialsDir: [path.join(__dirname, './views/partial'), `${doraemon}/partial`],
helpers: global.yoho.helpers
}));
... ...
/**
* Created by jing.li@yoho.cn.
* User: jing.li
* Date: 2016/9/5
* Time: 17:48
*/
'use strict';
const api = global.yoho.API;
const serviceAPI = global.yoho.ServiceAPI;
const singleAPI = global.yoho.SingleAPI;
const helpers = global.yoho.helpers;
const camelCase = global.yoho.camelCase;
const _ = require('lodash');
/**
* 逛分类
*/
const _category = () => {
return serviceAPI.get('/guang/api/v1/category/get', {
}, {
code: 200
});
};
/**
* 逛内容列表
*/
const _article = (param) => {
return serviceAPI.get('/guang/api/v2/article/getList', {
gender: param.gender,
page: param.page || 1,
uid: param.uid,
udid: param.udid,
sort_id: param.type ? param.type : 1,
tag: param.tag ? param.tag : null,
author_id: param.authorId ? param.authorId : null,
limit: param.limit ? param.limit : null,
}, {
code: 200
}).then(result => {
return result;
});
};
/**
* 逛
* @param params
*/
const getArticle = (param) => {
let page = param.page ? param.page : 1;
Object.assign(param, { page: page });
return api.all([
_category(),
_article(param)
]).then(result => {
let resu = {
guang: {
infos: [{
show: true,
info: [{
'article_type': '1',
author: {
author_id: '8168296',
avatar: 'http://img10.static.yhbimg.com/author/2016/05/07/15/01bb3ae789c573502830726c3297d0c80a.png',
name: '雾萌萌',
url: 'http://guang.m.yohobuy.com/author/index?id=8168296'
},
'author_id': '8168296',
'category_id': '1',
'category_name': '话题',
'conver_image_type': '1',
'id': 34380,
text: '验证逛文章图片压缩测试验证逛文章图片压缩测试验证逛文章图片压缩测试',
'isFavor': 'N',
'isPraise': 'N',
'is_recommended': '1',
'praiseStatus': 'true',
'praise_num': '0',
publishTime: '09月02日 19:21',
'share': {
'url': 'http://guang.m.yohobuy.com/info/index?id=34380'
},
img: 'https://img13.static.yhbimg.com/article/2016/09/05/14/02d732942cdd9647465736cb79796b0ddd.jpg?imageView/2/w/640/h/640',
'title': '验证逛文章图片压缩测试',
'url': 'http://guang.m.yohobuy.com/info/index?id=34380',
pageView: '50'
}]
}],
navs: [{
typeId: '0',
type: '推荐',
focus: true
}, {
typeId: '1',
type: '话题'
}, {
typeId: '2',
type: '搭配'
}, {
typeId: '3',
type: '潮人'
}, {
typeId: '4',
type: '潮品'
}, {
typeId: '19',
type: '专题'
}],
swiper: [{
img: 'https://img11.static.yhbimg.com/yhb-img01/2016/09/01/10/017b5ce31285f9062469303ba9ca197660.jpg?imageView2/2/w/830/h/327',
url: 'http://feature.yoho.cn/0418RUNNINGMAN/index.html?title=兄弟在奔跑,潮流在有货&share_id=944'
}, {
img: 'https://img11.static.yhbimg.com/yhb-img01/2016/09/01/10/017b5ce31285f9062469303ba9ca197660.jpg?imageView2/2/w/830/h/327',
url: 'http://feature.yoho.cn/0418RUNNINGMAN/index.html?title=兄弟在奔跑,潮流在有货&share_id=944'
}]
}
};
return resu;
});
};
module.exports = {
getArticle
};
... ...
... ... @@ -57,7 +57,7 @@ const _processIndexData = (dataList) => {
if (list.ads) {
_.forEach(list.ads.data, (data) => {
formatData.ads.push({
src: data.src.replace('imageView', 'imageView2'),
src: data.src.replace('imageView/', 'imageView2/'),
url: data.url
});
});
... ... @@ -81,7 +81,7 @@ const _processIndexData = (dataList) => {
avatar.tags.push({
avatarUrl: `/guang/star/detail?tag=${tags.tagName}&openby:yohobuy{"action":"go.h5","params":{"id":"","share":"","shareparam":{},"islogin":"N","type":0,"updateflag":"N","url":"http://m.yohobuy.com/guang/star/detail","param":{"tag":"${tags.tagName}"}}}`, // eslint-disable-line
cover: tags.cover ? (tags.cover + '?imageView2/2/w/104/h/104/q/80') : tags.cover,
cover: tags.cover ? (tags.cover + '?imageView2/2/w/104/h/104') : tags.cover,
tagName: tags.tagName
});
});
... ... @@ -96,7 +96,7 @@ const _processIndexData = (dataList) => {
url: data.url,
title: data.title,
articeTxt: data.intro,
src: data.src + '/q/80',
src: data.src,
publishTime: helpers.dateFormat('MM月DD日 hh:mm', data.publishTime),
viewsNum: data.viewsNum
}, avatar));
... ... @@ -106,13 +106,13 @@ const _processIndexData = (dataList) => {
// 首页明星头像数据处理
if (list.tags) {
_.forEach(list.tags, (data) => {
_.forEach(list.tags, (data, index) => {
let url = `/guang/star/detail?tag=${data.tagName}&openby:yohobuy{"action":"go.h5","params":{"id":"","share":"","shareparam":{},"islogin":"N","type":0,"updateflag":"N","url":"http://m.yohobuy.com/guang/star/detail","param":{"tag":"${data.tagName}"}}}`; // eslint-disable-line
formatData.starAvatar.push({
// noLazy: index < 5,
//noLazy: index < 6,
url: url,
cover: data.cover ? (data.cover + '?imageView2/2/w/180/h/180/q/80') : data.cover
cover: data.cover ? (data.cover + '?imageView2/2/w/180/h/180') : data.cover
});
});
}
... ... @@ -213,7 +213,7 @@ const getSpecialData = () => {
return;
}
item.src += '/q/80';
// item.src += '/q/80';
if (key < 4) {
item.islazy = true;
... ...
... ... @@ -10,7 +10,7 @@ const express = require('express');
const cRoot = './controllers';
const star = require(cRoot + '/star');
const plusstar = require(cRoot + '/plusstar');
const homeController = require(`${cRoot}/index`);
const router = express.Router(); // eslint-disable-line
router.get('/star', star.index); // 星潮教室首页
... ... @@ -25,5 +25,6 @@ router.post('/star/setFavorite', star.setFavorite); // 收藏文章
router.get('/plusstar', plusstar.index); // 潮流优选
router.get('/plusstar/resources-template', plusstar.resourcesTemplate); // 潮流优选首页-资源位
router.get('/', homeController.index); // 逛首页
module.exports = router;
... ...
<div class="guang-list-page guang-page yoho-page">
{{# guang}}
<ul id="guang-nav" class="guang-nav clearfix">
{{# navs}}
<li class="guang-nav-item {{#focus}}focus{{/focus}}" data-type={{typeId}}>
{{type}}
</li>
{{/ navs}}
</ul>
<div id="info-list" class="info-list-container">
{{# infos}}
<div class="info-list{{^show}} hide{{/show}}">
{{#if show}}
{{#if ../swiper}}
<div class="swiper-container swiper-cont-{{typeId}}">
<div class="swiper-wrapper swiper-wrap-{{typeId}}">
{{# swiper}}
<div class="swiper-slide">
<a href="{{url}}">
<img class="swiper-lazy" data-src="{{img}}">
</a>
<div class="swiper-lazy-preloader"></div>
</div>
{{/ swiper}}
</div>
<div class="swiper-pagination swiper-pagi-{{typeId}}"></div>
</div>
{{/if}}
{{/if}}
{{# info}}
{{> info}}
{{/ info}}
</div>
{{/ infos}}
</div>
<div id="load-more-info" class="load-more-info">
<div class="loading status hide">
正在加载...
</div>
<span class="no-more status">没有更多啦</span>
</div>
<input id="gender" type="hidden" value={{gender}}>
{{/ guang}}
</div>
\ No newline at end of file
... ...
<div class="guang-info" data-id="{{id}}">
{{# author}}
<a class="info-author clearfix" href={{url}}>
<img class="lazy avatar" data-original={{avatar}}>
<span class="name">{{name}}</span>
</a>
{{/ author}}
<div class="info-img">
{{#if showTags}}
<a href="javascript:;" class="info-match">
{{# isTip}}
小贴士
<div class="info-tag tip"></div>
{{/ isTip}}
{{# isCollocation}}
搭配
<div class="info-tag collocation"></div>
{{/ isCollocation}}
{{# isFashionMan}}
潮人
<div class="info-tag fashion-man"></div>
{{/ isFashionMan}}
{{# isFashionGood}}
潮品
<div class="info-tag fashion-good"></div>
{{/ isFashionGood}}
{{# isTopic}}
话题
<div class="info-tag topic"></div>
{{/ isTopic}}
{{# isSpecialTopic}}
专题
<div class="info-tag special-topic"></div>
{{/ isSpecialTopic}}
</a>
{{/if}}
<a href="{{url}}">
<img class="lazy" data-original="{{img}}" alt="{{alt}}">
</a>
</div>
<div class="info-deps">
<a class="info-title-container" href="{{url}}">
<h2 class="info-title">{{title}}</h2>
</a>
<p class="info-text">{{text}}</p>
{{> guang/tvls}}
</div>
</div>
\ No newline at end of file
... ...
<div class="guang-list-page guang-page yoho-page">
{{# guang}}
{{# authorInfo}}
<div id="author-infos" class="editor-header clearfix" data-id={{id}}>
<div class="avatar">
<img src="{{avatar}}">
</div>
<div class="text">
<p class="name">{{name}}</p>
<p class="info">{{info}}</p>
</div>
</div>
{{/ authorInfo}}
<div id="info-list" class="info-list">
{{# infos}}
{{> guang/info}}
{{/ infos}}
</div>
<div id="load-more-info" class="load-more-info">
<div class="loading status hide">
正在加载...
</div>
<span class="no-more status">没有更多啦</span>
</div>
{{#if tag}}
<input id="tag" type="hidden" value={{tag}}>
{{/if}}
{{#if gender}}
<input id="gender" type="hidden" value={{gender}}>
{{/if}}
{{#if isApp}}
<input id="isApp" type="hidden" value={{isApp}}>
{{/if}}
{{/ guang}}
</div>
\ No newline at end of file
... ...
info
<div class="guang-info" data-id="{{id}}">
{{# author}}
<a class="info-author clearfix" href={{url}}>
<img class="lazy avatar" data-original={{avatar}}>
<span class="name">{{name}}</span>
</a>
{{/ author}}
<div class="info-img">
{{#if showTags}}
<a href="javascript:;" class="info-match">
{{# isTip}}
小贴士
<div class="info-tag tip"></div>
{{/ isTip}}
{{# isCollocation}}
搭配
<div class="info-tag collocation"></div>
{{/ isCollocation}}
{{# isFashionMan}}
潮人
<div class="info-tag fashion-man"></div>
{{/ isFashionMan}}
{{# isFashionGood}}
潮品
<div class="info-tag fashion-good"></div>
{{/ isFashionGood}}
{{# isTopic}}
话题
<div class="info-tag topic"></div>
{{/ isTopic}}
{{# isSpecialTopic}}
专题
<div class="info-tag special-topic"></div>
{{/ isSpecialTopic}}
</a>
{{/if}}
<a href="{{url}}">
<img class="lazy" data-original="{{img}}" alt="{{alt}}">
</a>
</div>
<div class="info-deps">
<a class="info-title-container" href="{{url}}">
<h2 class="info-title">{{title}}</h2>
</a>
<p class="info-text">{{text}}</p>
{{> tvls}}
</div>
</div>
\ No newline at end of file
... ...
... ... @@ -11,19 +11,22 @@
<ul class="clearfix swiper-wrapper">
{{# starAvatar}}
<li class="swiper-slide">
{{#if noLazy}}
<a href='{{url}}' class="star" style="background: url('{{image cover 180 180}}')">
</a>
{{else}}
<a href='{{url}}' class="star swiper-lazy" data-background="{{image cover 180 180}}">
<a href='{{url}}'>
{{#if noLazy}}
<img class="star" src="{{cover}}">
{{else}}
<img class="star swiper-lazy" data-src="{{cover}}">
{{/if}}
</a>
{{/if}}
</li>
{{/ starAvatar}}
</ul>
</div>
</div>
<ul class="star-info clearfix">
{{#each articles}}
<li data-id="{{id}}">
... ...
<div class="time-view-like-share clearfix">
<i class="iconfont">&#xe603;</i>
{{publishTime}}&nbsp;&nbsp;&nbsp;&nbsp;
<i class="iconfont">&#xe602;</i>
<span class="page-view">{{pageView}}</span>
<div class="like-share-container">
{{# like}}
<i class="iconfont like-btn{{#isLiked}} like{{/isLiked}}">&#xe601;</i>
<span class="like-count">{{count}}</span>
{{/ like}}
{{# collect}}
<a href={{url}}>
<i class="iconfont collect-btn{{#isCollected}} collected{{/isCollected}}">&#xe605;</i>
</a>
{{/ collect}}
{{# share}}
<a href="{{.}}" class="iconfont share-btn">&#xe600;</a>
{{/ share}}
</div>
</div>
\ No newline at end of file
... ...
... ... @@ -9,8 +9,14 @@ const installmentModel = require('../models/installment');
const _ = require('lodash');
const helpers = global.yoho.helpers;
// 服务器报错页面
const _serverCrash = (res, params) => {
params.title = params.title || '有货分期';
res.render('installment/server-crash', params);
};
// 判断是否已经获取到了开通的状态值
const _reviewStatus = (uid, status, next) => {
const _reviewStatus = (res, req, uid, status) => {
let jumpUrl = helpers.appUrlFormat('/product/new', 'go.new');
if (status === '1') {
... ... @@ -27,17 +33,33 @@ const _reviewStatus = (uid, status, next) => {
success: {
price: result[1].currCreditLimit,
installmentOnly: {
title: '分期专享',
title: {
title: '分期专享',
moreUrl: helpers.appUrlFormat(req.originalUrl, 'go.instalmentlist', {
title: '分期专享'
})
},
goods: result[0]
},
url: jumpUrl
url: helpers.appUrlFormat(req.originalUrl, 'go.instalmentlist', {
title: '分期专享'
})
}
};
}).catch(next);
}).catch(() => {
_serverCrash(res, {
url: req.originalUrl,
title: '分期专享'
});
});
} else if (status === '3') {
return {
error: {
error: true
};
} else if (status === '4') {
return {
cancel: {
url: jumpUrl
}
};
... ... @@ -45,7 +67,7 @@ const _reviewStatus = (uid, status, next) => {
};
// 还款列表公共处理块
const _repaymentList = (req, res, next, title, params) => {
const _repaymentList = (req, res, title, params) => {
params = _.assign({
uid: req.cookies.installmentUid || 1
}, params);
... ... @@ -58,11 +80,16 @@ const _repaymentList = (req, res, next, title, params) => {
title: title,
data: result
});
}).catch(next);
}).catch(() => {
_serverCrash(res, {
url: req.originalUrl,
title: title
});
});
};
// 开通分期首页
const index = (req, res, next) => {
const index = (req, res) => {
let uid = req.query.uid;
Promise.all([installmentModel.getStauts(uid), installmentModel.getSearchIntallment({
... ... @@ -72,7 +99,12 @@ const index = (req, res, next) => {
// status:0 未申请 1审核中 2已开通 3 审核未通过
let openStatus = result[0];
let installmentOnly = {
title: '分期专享',
title: {
title: '分期专享',
moreUrl: helpers.appUrlFormat(req.originalUrl, 'go.instalmentlist', {
title: '分期专享'
})
},
goods: result[1]
};
... ... @@ -105,7 +137,7 @@ const index = (req, res, next) => {
return params;
});
} else if (openStatus === '1' || openStatus === '3') {
} else if (openStatus === '1' || openStatus === '3' || openStatus === '4') {
res.redirect('/home/installment/review?status=' + openStatus);
}
}).then((result) => {
... ... @@ -115,11 +147,15 @@ const index = (req, res, next) => {
isInstallmentPage: true,
title: '有货分期'
}, result));
}).catch(next);
}).catch(() => {
_serverCrash(res, {
url: req.originalUrl
});
});
};
// ajax 请求分期专享商品
const getInstallmentGoods = (req, res, next) => {
const getInstallmentGoods = (req, res) => {
let params = req.query || {};
installmentModel.getSearchIntallment(params).then((result) => {
... ... @@ -131,11 +167,15 @@ const getInstallmentGoods = (req, res, next) => {
} else {
res.json();
}
}).catch(next);
}).catch(() => {
_serverCrash(res, {
url: req.originalUrl
});
});
};
// 开通结果显示
const review = (req, res, next) => {
const review = (req, res) => {
let openStatus = req.query.status || false;
let uid = req.query.uid;
let data = {
... ... @@ -145,38 +185,38 @@ const review = (req, res, next) => {
};
if (openStatus !== '2') {
res.render('installment/open-result', _.assign(data, _reviewStatus(uid, openStatus)));
res.render('installment/open-result', _.assign(data, _reviewStatus(res, req, uid, openStatus)));
} else {
_reviewStatus(uid, openStatus, next).then((params) => {
_reviewStatus(res, req, uid, openStatus).then((params) => {
res.render('installment/open-result', _.assign(data, params));
});
}
};
// 逾期未还款列表
const overdueList = (req, res, next) => {
_repaymentList(req, res, next, '逾期未还金额', {
const overdueList = (req, res) => {
_repaymentList(req, res, '逾期未还金额', {
queryDays: -1
});
};
// 7日待还款列表
const sevenDayList = (req, res, next) => {
_repaymentList(req, res, next, '近7日待还款', {
const sevenDayList = (req, res) => {
_repaymentList(req, res, '近7日待还款', {
queryDays: 7
});
};
// 本月待还款列表
const monthRepayList = (req, res, next) => {
_repaymentList(req, res, next, '本月待还金额', {
const monthRepayList = (req, res) => {
_repaymentList(req, res, '本月待还金额', {
queryDays: 30
});
};
// 待还总金额列表
const totalRepayList = (req, res, next) => {
_repaymentList(req, res, next, '待还总金额', {
const totalRepayList = (req, res) => {
_repaymentList(req, res, '待还总金额', {
queryDays: 0
});
};
... ... @@ -192,7 +232,7 @@ const repayRecordPage = (req, res) => {
};
// ajax 请求还款记录
const getRepayRecord = (req, res, next) => {
const getRepayRecord = (req, res) => {
let params = _.assign({
uid: req.cookies.installmentUid || 1,
pageNo: req.query.page || 1
... ... @@ -207,21 +247,49 @@ const getRepayRecord = (req, res, next) => {
} else {
res.json();
}
}).catch(next);
}).catch(() => {
_serverCrash(res, {
url: req.originalUrl,
title: '还款记录'
});
});
};
// 账号管理
const account = (req, res, next) => {
let uid = req.cookies.installmentUid || 512579468;
const account = (req, res) => {
res.render('installment/account', {
title: '账号管理',
isInstallmentPage: true
});
};
installmentModel.getBankCards(uid).then((result) => {
res.render('installment/account', {
accountList: result,
title: '账号管理',
isInstallmentPage: true,
repaymentList: result
// 添加新银行卡
const bindCard = (req, res) => {
res.render('installment/bind-card', {
module: 'home',
page: 'bind-card',
title: '使用新卡还款',
bindCard: {
userName: req.query.name
},
isInstallmentPage: true
});
};
// 添加新银行卡请求
const postAccount = (req, res) => {
var params = _.assign({
uid: req.cookies.installmentUid
}, req.query);
installmentModel.postAccount(params).then((result) => {
res.json(result);
}).catch(() => {
_serverCrash(res, {
url: req.originalUrl,
title: '使用新卡还款'
});
}).catch(next);
});
};
const startingService = (req, res) => {
... ... @@ -247,7 +315,7 @@ function getRealIP(req) {
return realIP || forwardedFor.split(',')[0] || req.connection.remoteAddress;
}
const activateService = (req, res, next) => {
const activateService = (req, res) => {
installmentModel.activateService({
uid: req.cookies.installmentUid || 532892,
... ... @@ -263,22 +331,35 @@ const activateService = (req, res, next) => {
ip: getRealIP(req)
}).then((result)=> {
res.json(result);
}).catch(next);
}).catch(() => {
_serverCrash(res, {
url: req.originalUrl,
title: '开通有货分期'
});
});
};
const getBankInfo = (req, res, next) => {
const getBankInfo = (req, res) => {
installmentModel.getBankInfo({
cardNo: req.query.cardNo,
uid: req.cookies.installmentUid || 512579468 // TODO: fix uid
}).then((result)=> {
res.json(result);
}).catch(next);
}).catch(() => {
_serverCrash(res, {
url: req.originalUrl
});
});
};
const verifyCode = (req, res, next) => {
const verifyCode = (req, res) => {
installmentModel.sendVerifyCode(req.cookies.installmentUid || 1, req.query.mobile).then((result)=> {
res.json(result);
}).catch(next);
}).catch(() => {
_serverCrash(res, {
url: req.originalUrl
});
});
};
const orderIndex = (req, res) => {
... ... @@ -291,7 +372,7 @@ const orderIndex = (req, res) => {
});
};
const orderList = (req, res, next) => {
const orderList = (req, res) => {
const params = {
uid: req.cookies.installmentUid || 8041876, // TODO: fix me
type: req.query.type || 1,
... ... @@ -319,10 +400,15 @@ const orderList = (req, res, next) => {
layout: false,
isInstallmentPage: true
});
}).catch(next);
}).catch(() => {
_serverCrash(res, {
url: req.originalUrl,
title: '我的分期订单'
});
});
};
const orderDetail = (req, res, next) => {
const orderDetail = (req, res) => {
const params = {
uid: req.cookies.installmentUid || 8041876, // TODO: fix me
orderCode: req.params.id
... ... @@ -405,11 +491,16 @@ const orderDetail = (req, res, next) => {
}
}
});
}).catch(next);
}).catch(() => {
_serverCrash(res, {
url: req.originalUrl,
title: '分期详情'
});
});
};
// 还款详情
const repayDetail = (req, res, next) => {
const repayDetail = (req, res) => {
let params = {
uid: req.cookies.installmentUid || 512579468,
rePayNo: req.query.id || '',
... ... @@ -422,7 +513,12 @@ const repayDetail = (req, res, next) => {
isInstallmentPage: true,
isOne: true
}, result[0]));
}).catch(next);
}).catch(() => {
_serverCrash(res, {
url: req.originalUrl,
title: '还款详情'
});
});
};
// 帮助静态页面
... ... @@ -440,17 +536,48 @@ const agreement = (req, res) => {
};
// 计算金额
const totalAmount = (req, res, next) => {
const totalAmount = (req, res) => {
installmentModel.totalAmount(req.query.prices).then((result) => {
res.json(result);
}).catch(next);
}).catch(() => {
_serverCrash(res, {
url: req.originalUrl
});
});
};
// 检查验证码
const checkVerifyCode = (req, res, next) => {
const checkVerifyCode = (req, res) => {
installmentModel.checkVerifyCode(req.cookies.installmentUid, req.query.mobile, req.query.code).then((result) => {
res.json(result);
}).catch(next);
}).catch(() => {
_serverCrash(res, {
url: req.originalUrl
});
});
};
// 服务器崩溃
const serverCrash = (req, res) => {
res.render('installment/server-crash');
};
// 银行卡列表
const bankCard = (req, res) => {
let uid = req.cookies.installmentUid || 512579468;
installmentModel.getBankCards(uid).then((result) => {
res.render('installment/bank-card', {
title: '我的银行卡',
isInstallmentPage: true,
accountList: result
});
}).catch(() => {
_serverCrash(res, {
url: req.originalUrl,
title: '我的银行卡'
});
});
};
module.exports = {
... ... @@ -475,5 +602,9 @@ module.exports = {
agreement,
totalAmount,
checkVerifyCode,
getInstallmentGoods
getInstallmentGoods,
bindCard,
serverCrash,
bankCard,
postAccount
};
... ...
... ... @@ -107,7 +107,6 @@ const _processAmtList = (listData, queryDays) => {
// 处理还款记录数据
const _processRepayList = (list) => {
if (list !== 'NULL') {
_.forEach(list.rePayList, (data) => {
if (data.status === 1) {
... ... @@ -464,6 +463,7 @@ const checkVerifyCode = (uid, mobile, code) => {
method: method,
mobile: mobile,
snsCheckCode: code,
codeType: 1, // 授信
debug: 'XYZ'
}, {
timeout: API_TIMEOUT
... ... @@ -472,6 +472,16 @@ const checkVerifyCode = (uid, mobile, code) => {
});
};
// 添加银行卡请求
const postAccount = (params) => {
return api.get('', _.assign({
method: 'user.instalment.bindingCards',
debug: 'XYZ'
}, params), {
timeout: 6000
});
};
module.exports = {
getStauts,
getQueryCreditInfo,
... ... @@ -487,5 +497,6 @@ module.exports = {
getInstallmentOrders,
getInstallmentOrderDetail,
totalAmount,
checkVerifyCode
checkVerifyCode,
postAccount
};
... ...
... ... @@ -18,7 +18,7 @@ const personalController = require(`${cRoot}/qrcode`);
router.get('/QRcode/:id', personalController.QRcode);
// 分期付款
router.get('/installment/index', installment.index);// 开通分期首页
router.get('/installment/index', installment.index); // 开通分期首页
router.get('/installment/review', installment.review); // 开通分期首页
router.get('/installment/starting-service', installment.startingService); // 分期付款开通
router.get('/installment/starting-service/verify-code', installment.verifyCode);
... ... @@ -34,6 +34,8 @@ router.get('/installment/repay/get-record', installment.getRepayRecord); // ajax
router.get('/installment/repay/detail', installment.repayDetail); // 还款详情
router.get('/installment/account', installment.account); // 账户管理
router.get('/installment/bind-card', installment.bindCard); // 添加新银行卡
router.get('/installment/post-account', installment.postAccount); // 添加新卡请求
router.get('/installment/bank-info', installment.getBankInfo);
router.post('/installment/activate-service', installment.activateService);
router.get('/installment/order', installment.orderIndex);
... ... @@ -42,6 +44,8 @@ router.get('/installment/order/:id', installment.orderDetail);
router.get('/installment/total-amount.json', installment.totalAmount);
router.get('/installment/help', installment.help);// 帮助静态页面
router.get('/installment/agreement', installment.agreement);// 服务协议\服务条款静态页面
router.get('/installment/agreement', installment.agreement);// 服务协议静态页面
router.get('/installment/server-crash', installment.serverCrash); // 服务器崩溃
router.get('/installment/bank-card', installment.bankCard); // 银行卡列表
module.exports = router;
... ...
<div class="account-page">
<ul class="account-list">
{{#accountList}}
<li>我的银行卡:<div class="list-right">{{cardNo}}</div></li>
{{/accountList}}
<li><a href="/home/installment/bank-card">我的银行卡:<div class="list-right"><span class="iconfont">&#xe604;</span></div></a></li>
</ul>
</div>
\ No newline at end of file
</div>
... ...
This diff could not be displayed because it is too large.
<div class="bank-card-page">
<ul class="bank-card-list">
{{#accountList}}
<li class="card-bg-{{lowerCase bankCode}}"><span>{{cardNo}}</span></li>
{{/accountList}}
</ul>
</div>
... ...
<div class="installment-page add-account-page yoho-page">
{{#bindCard}}
<ul class="add-form">
<li>
<label>持卡人</label>
<div class="username">{{userName}}</div>
</li>
<li>
<label>银行卡</label>
<input id="cardNo" name="cardNo" type="tel" placeholder="请输入本人银行卡号" size="26" maxlength="23">
</li>
<li id="bank-desc" style="display: none;">
<div class="bank-info">
<img id="bank-icon" src="" alt="">
<span id="bank-name"></span>
</div>
</li>
<li>
<label>手机号</label>
<input type="number" placeholder="请输入银行预留手机号" id="mobile" name="mobile" pattern="\d*" maxlength="11">
</li>
</ul>
<a href="" class="open-btn disabled">下一步</a>
<a href="" class="jumpResult">&nbsp;</a>
{{/bindCard}}
<div class="success">
<i class="success-icon"></i>
<p class="success-txt">恭喜您,新增还款银行卡成功!</p>
<a href="" class="open-btn">确认</a>
</div>
<div class="error">
<i class="error-icon"></i>
<p class="error-txt1">对不起,绑定银行卡失败</p>
<p class="error-txt2">失败的原因可能是:银行卡户名、<br/>银行卡、预留手机号不一致</p>
<a href="{{url}}" class="open-btn">重新绑定银行卡</a>
<p class="contact-cs">如有疑问,请联系客服</p>
</div>
</div>
... ...
... ... @@ -143,5 +143,4 @@
如您在使用有货分期过程中遇到还款及资金安全方面问题您可联系信而富客服为,您进行相关处理和解答,联系电话:400-688-8692(工作日9:00-18:00),如您无法联系信而富客服您可联系有货客服,我们将在3个工作日内给您回复,感谢您的理解与支持!
</p>
</div>
</div>
... ...
... ... @@ -35,7 +35,7 @@
<p class="detail-txt1">近7日待还款</p>
<p class="detail-txt1">¥<span class="detail-txt2">{{dayAmt}}</span></p>
{{#if isOverdue}}
<p class="detail-txt3">您有¥{{overAmt}}已逾期,点击<a href="/home/installment/repay/overdue">查看详情</a></p>
<p class="detail-txt3">您有¥{{overAmt}}已逾期,点击<a href="/home/installment/repay/overdue">查看详情</a></p>
{{/if}}
<a href="/home/installment/repay/7daylist" class="see-btn">明细</a>
</div>
... ...
... ... @@ -20,10 +20,19 @@
{{/ success}}
{{# error}}
<div class="error">
<i class="success-icon"></i>
<p class="error-txt1">审核未通过,暂时无法授信</p>
<p class="error-txt2">在有货更多的消费,增加信用度,<br>会大大提升审核通过率噢</p>
<a href="{{url}}" class="open-btn">去逛逛</a>
<i class="error-icon"></i>
<p class="error-txt1">审核未通过暂时无法授信</p>
<p class="error-txt2">可能原因:姓名、身份证、银行卡不匹配</p>
<a href="/home/installment/starting-service" class="open-btn">重新申请</a>
</div>
{{/ error}}
{{#cancel}}
<div class="cancel">
<i class="cancel-icon"></i>
<p class="cancel-txt1">账户已注销</p>
<p class="cancel-txt2">您的有货分期账户经本人确认已注销,<br>如有疑问,请联系客服。<br>提示:已注销用户不可再开通</p>
<p></p>
<a href="{{url}}" class="open-btn">先去逛逛</a>
</div>
{{/cancel}}
</div>
... ...
... ... @@ -90,5 +90,4 @@
{{#isRepaymentAllCompleted order.status}}
<div class="all-completed">已还清</div>
{{/isRepaymentAllCompleted}}
</div>
</div>
\ No newline at end of file
... ...
... ... @@ -21,4 +21,3 @@
</li>
{{/each}}
{{/if}}
... ...
... ... @@ -13,7 +13,7 @@
<input id="list-{{key}}" type="checkbox" class="installment-check-btn" {{#if isChecked}}checked{{/if}}/>
<label for="list-{{key}}">
<div class="cont">
<p>¥{{currNoFeeAmt}}</p>
<p>¥{{currAmt}}</p>
<p>【全{{stage}}期】{{billInfo}}</p>
</div>
</label>
... ... @@ -32,5 +32,5 @@
</ul>
{{> installment/repayment-bottom}}
{{/if}}
{{/data}}
{{/data}}
</div>
... ...
<div class="installment-page">
<div class="server-crash">
<i class="refresh-icon"></i>
<p>接口调用失败,服务器可能累了,<br>重新加载给个鼓励吧!</p>
<a href="{{url}}" class="open-btn">重新加载</a>
</div>
</div>
... ...
... ... @@ -53,7 +53,7 @@
</div>
<div class="agreements">
<input id="accept-agreements" name="agreements" type="checkbox" class="installment-check-btn"/>
<input id="accept-agreements" name="agreements" type="checkbox" class="installment-check-btn" checked/>
<label for="accept-agreements">
<div class="text-label">免费开通,详情请见
<a id="agreements" href="" data-href="/home/installment/agreement">《有货分期-信而富用户服务协议&借款服务协议》</a>
... ...
<div class="installment-only">
<h2>{{title}}</h2>
{{!--<h2>{{title}}</h2>--}}
{{> common/floor-header-more}}
<div id="goods-list" class="goods-list clearfix">
{{# goods}}
{{> common/goods}}
... ...
... ... @@ -23,7 +23,7 @@ const indexEmailPage = (req, res) => {
page: 'back-email',
title: '找回密码-通过邮箱'
}, {
backUrl: SIGN_IN,
// backUrl: SIGN_IN,
headerText: '找回密码',
isPassportPage: true,
backEmail: true
... ... @@ -100,7 +100,7 @@ const backSuccessByEmailPage = (req, res) => {
page: 'back-email-success',
title: '找回密码-通过邮箱'
}, {
backUrl: helpers.urlFormat('/passport/back/email'),
// backUrl: helpers.urlFormat('/passport/back/email'),
headerText: '找回密码',
isPassportPage: true,
backEmailSuccess: true,
... ... @@ -145,7 +145,7 @@ const indexMobilePage = (req, res, next) => {
page: 'back-mobile',
title: '找回密码-通过手机号'
}, {
backUrl: SIGN_IN,
// backUrl: SIGN_IN,
headerText: '找回密码',
isPassportPage: true,
backMobile: true,
... ... @@ -203,7 +203,7 @@ const verifyCodeByMobilePage = (req, res) => {
page: 'back-code',
title: '找回密码-通过手机号'
}, {
backUrl: helpers.urlFormat('/passport/back/mobile'),
// backUrl: helpers.urlFormat('/passport/back/mobile'),
headerText: '找回密码',
isPassportPage: true,
backCode: true,
... ... @@ -261,7 +261,7 @@ const setNewPasswordByMobilePage = (req, res) => {
page: 'back-new-password',
title: '找回密码-输入新密码'
}, {
backUrl: SIGN_IN,
// backUrl: SIGN_IN,
headerText: '找回密码',
isPassportPage: true,
backNewPwd: true,
... ...
/* eslint no-unused-vars: ["error", { "args": "none" }] */
/**
* 登录
* @author: Bi Kai<kai.bi@yoho.cn>
... ... @@ -93,6 +94,7 @@ const local = {
backUrl: 'javascript:history.go(-1)', // eslint-disable-line
showHeaderImg: true, // 控制显示头部图片
isPassportPage: true, // 模板中模块标识
smsLoginUrl: '/passport/sms_login',
registerUrl: '/passport/reg/index', // 注册的URL链接
aliLoginUrl: '/passport/login/alipay', // 支付宝快捷登录的URL链接
weiboLoginUrl: '/passport/login/sina', // 微博登录的URL链接
... ...
/* eslint no-unused-vars: ["error", { "args": "none" }] */
'use strict';
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');
// constrant
const CODE_REQUIRED = '请输入校验码';
const PASSWORD_REQUIRED = '请输入密码';
const PASSWORD_LENGTH_ERROR = '密码6-20位,请重新输入';
const BAD_PASSWORD = '密码格式不正确';
const TOO_MANY = '请求太频繁';
const LOGIN_SUCCSS = '登录成功';
const VERIFY_ERROR = '校验失败';
exports.beforeIn = (req, res, next) => {
res.set({
'Cache-Control': 'no-cache, no-store, must-revalidate',
Pragma: 'no-cache',
Expires: 0
});
if (!req.xhr && req.user.uid) {
return res.redirect(req.cookies.refer);
}
next();
};
// 短信登录 第一步: 展现页面
const _step1 = (req, res, next) => {
let template = 'sms/login';
let viewData = {
module: 'passport',
page: 'sms-login',
title: '手机短信登录',
isPassportPage: true,
headerText: '手机号码快捷登录',
areaCode: '+86', // 默认的区号
countrys: RegService.getAreaData() // 地区信息列表
};
res.render(template, viewData);
};
// 短信登录 第二步: 输入 校验码
const _step2 = (req, res, next) => {
const mobile = req.session.smsLogin.mobile;
const area = req.session.smsLogin.area;
const interval = req.session.smsLogin.interval;
const template = 'sms/check';
const viewData = {
module: 'passport',
page: 'sms-check',
title: '手机短信登录',
isPassportPage: true,
headerText: '手机号码快捷登录',
canResend: interval < Date.now(),
mobile,
area
};
res.render(template, viewData);
};
// 短信登录 第三步: 设置密码 (针对 改手机未注册用户)
const _step3 = (req, res, next) => {
const template = 'sms/password';
const viewData = {
module: 'passport',
page: 'sms-password',
title: '设置密码',
isPassportPage: true,
headerText: '设置密码'
};
res.render(template, viewData);
};
// 短信 登录
exports.loginPage = (req, res, next) => {
let step = Number(req.query.step) || 1;
let smsLoginStep = req.session.smsLoginStep || 1;
if (step === 2 && smsLoginStep !== 2) {
return res.redirect(req.path);
}
if (step === 3 && smsLoginStep !== 3) {
return res.redirect(req.path);
}
switch (step) {
case 2:
_step2(req, res, next);
break;
case 3:
_step3(req, res, next);
break;
case 1:
default:
_step1(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();
if (!req.xhr) {
return next(404);
}
if (req.session.smsLogin && req.session.smsLogin.interval > Date.now()) {
return res.json({
code: 429,
message: TOO_MANY
});
}
if ([area, mobile].some(val => val === '')) {
return res.json({
code: 401,
message: '请求参数,无法处理'
});
}
next();
};
// AJAX 获取验证码
exports.token = (req, res, next) => {
let area = req.query.area;
let mobile = req.query.mobile;
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
result.redirect = '/passport/sms_login?step=2';
res.json(result);
return;
}
res.json(result);
});
};
exports.checkBefore = (req, res, next) => {
let code = req.query.code = (req.query.code || '').trim();
if (!req.xhr && req.session.smsLoginStep !== 2) {
return next(404);
}
if (!code) {
return res.json({
code: 404,
message: CODE_REQUIRED
});
}
next();
};
// AJAX 校验验证码 in step2
exports.check = (req, res, next) => {
const code = req.query.code;
const mobile = req.session.smsLogin.mobile;
const area = req.session.smsLogin.area;
const shopping_key = cookie.getShoppingKey(req); // eslint-disable-line
Promise.all([
PhoneService.checkUserPhoneExist(mobile, area),
PhoneService.verifySMS(mobile, area, code, 1)
])
.then(result => {
let r1 = result[0] || {};
let r2 = result[1] || {};
let redirect;
// 验证码 校验异常
if (r2.code !== 200) {
res.json(r2);
return;
}
// 检测 手机号 是否注册 异常
if (r1.code !== 200) {
res.json(r1);
return;
}
// 校验失败
if (r2.data.is_pass !== 'Y') {
res.json({
code: 401,
message: VERIFY_ERROR
});
return;
}
// 手机号码 没注册
if (r1.data.is_register !== 'Y') {
redirect = '/passport/sms_login?step=3';
req.session.smsLoginStep = 3;
res.json({
code: 200,
redirect
});
return;
}
// 手机号码已注册 --> 直接登录
PhoneService.autoSignin({
profile: mobile,
code: r2.data.code,
area,
shopping_key
})
.then(info => {
if (info.code !== 200) {
return Promise.reject(info);
}
return AuthHelper.syncUserSession(info.data.uid, req, res);
})
.then(() => {
res.json({
code: 200,
message: LOGIN_SUCCSS,
redirect: req.cookies.refer
});
delete req.session.smsLogin;
delete req.session.smsLoginStep;
})
.catch(error => {
res.json(error);
});
})
.catch(next);
};
// AJAX 短信登录 设置密码 in step3
exports.password = (req, res, next) => {
if (req.session.smsLoginStep !== 3) {
return next();
}
let data = {
code: '400',
message: BAD_PASSWORD
};
let smsLogin = req.session.smsLogin || {};
let mobile = smsLogin.mobile;
let area = smsLogin.area;
let password = (req.body.password || '').trim();
if (!password) {
data.message = PASSWORD_REQUIRED;
return res.json(data);
}
if (password.length < 6 || password.length > 20) {
data.message = PASSWORD_LENGTH_ERROR;
return res.json(data);
}
if (!helpers.verifyPassword(password)) {
return res.json(data);
}
// 购物车key
let shoppingKey = cookie.getShoppingKey(req);
RegService.regMobileAes(area, mobile, password, shoppingKey).then(result => {
if (!result.code || result.code !== 200) {
return Promise.reject(result);
}
if (!result.data || !result.data.uid) {
return Promise.reject(result);
}
return AuthHelper.syncUserSession(result.data.uid, req, res);
}).then(() => {
res.json({
code: 200,
message: LOGIN_SUCCSS,
redirect: req.cookies.refer
});
delete req.session.smsLogin;
delete req.session.smsLoginStep;
}).catch(next);
};
... ...
/* eslint no-unused-vars: ["error", { "args": "none" }] */
'use strict';
const API = global.yoho.API;
class PhoneService {
// 校验 手机 是否 已注册
// http://git.yoho.cn/yoho-documents/api-interfaces/blob/master/个人中心/验证码登录/校验是否是注册用户.md
static checkUserPhoneExist(mobile, area) {
return API.get('', {
method: 'app.passport.checkUserExist',
mobile,
area
});
}
// 手机号 自动登录
// http://git.yoho.cn/yoho-documents/api-interfaces/blob/master/个人中心/验证码登录/手机号自动登录.md
static autoSignin(param) {
return API.get('', {
method: 'app.passport.autoSignin',
profile: param.profile,
area: param.area,
code: param.code,
shopping_key: param.shopping_key
});
}
// 发送 验证码
// http://git.yoho.cn/yoho-documents/api-interfaces/blob/master/个人中心/验证码登录/发送验证码.md
static sendSMS(mobile, area, type) {
if (process.env.NODE_ENV === 'development') {
return new Promise((resolve, reject) => {
return resolve({
alg: 'SALT_MD5',
code: 200,
data: {},
md5: '6d729d4b35f10fc73531210bd7ecff91',
message: '发送成功.'
});
});
}
return API.get('', {
method: 'app.message.sendSms',
mobile,
area,
type
});
}
// 校验 验证码
// http://git.yoho.cn/yoho-documents/api-interfaces/blob/master/个人中心/验证码登录/验证验证码.md
static verifySMS(mobile, area, code, type) {
if (process.env.NODE_ENV === 'development') {
return new Promise((resolve, reject) => {
return resolve({
alg: 'SALT_MD5',
code: 200,
data: {
is_pass: 'Y'
},
md5: '6d729d4b35f10fc73531210bd7ecff91',
message: '发送成功.'
});
});
}
return API.get('', {
method: 'app.message.verifySmsCode',
mobile,
area,
code,
type
});
}
}
module.exports = PhoneService;
... ...
... ... @@ -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 router = express.Router(); // eslint-disable-line
... ... @@ -33,6 +34,17 @@ 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.get('/passport/login/wechat', login.common.beforeLogin, login.wechat.login);
router.get('/passport/login/wechat/callback', login.wechat.callback);
... ...
... ... @@ -18,7 +18,7 @@
{{#if isWechatLogin}}
<div class="other-login">
<a href="/passport/login/index">
<a href="/passport/login">
用其他方式登录
</a>
</div>
... ...
... ... @@ -10,7 +10,7 @@
</div>
<span id="btn-login" class="btn btn-login disable">登录</span>
<p class="op-container">
<a class="go-register" href={{registerUrl}}>免费注册</a>
<a class="sms-login" href={{smsLoginUrl}}>手机号码快捷登录</a>
<span id="forget-pwd" class="forget-pwd">忘记密码</span>
</p>
<div class="third-party-login">
... ... @@ -22,6 +22,10 @@
</div>
</div>
<a class="international" href={{internationalUrl}}>International Customer</a>
<div class="go-register">
<i class="iconfont">&#xe610;</i>
<a href={{registerUrl}}>注册Yoho!Family</a>
</div>
<div class="login-tip">
<div class="info-icon"></div>
Yoho!Family账号可登录Yoho!Buy有货
... ...
<div class="sms-login sms-login-check passport-page yoho-page">
{{> passport/header}}
<div class="content">
<p class="sms-login-msg">验证码已发至&nbsp;<span class="tel">+{{area}} {{mobile}}</span></p>
<div class="input-container input-group sms-input row">
<input id="sms-code" class="input" type="text" placeholder="验证码">
<div class="input-addon">
<button type="button" id="resend-sms">重发验证码</button>
</div>
<button class="clear-input" type="button"></button>
</div>
<button id="btn-next" class="btn btn-next disable row" type="button">登录</button>
</div>
<input type="hidden" name="mobile" id="mobile" value="{{mobile}}">
<input type="hidden" name="area" id="area" value="{{area}}">
</div>
<script>
var canResend = {{canResend}};
</script>
\ No newline at end of file
... ...
<div class="sms-login-page passport-page yoho-page">
{{> passport/header}}
<div class="content">
{{> passport/country_list}}
<div class="input-container phone-container row has-clear">
<span id="area-code" class="area-code">{{areaCode}}</span>
<input id="phone-num" class="input phone-num" type="text" placeholder="手机号">
<button class="clear-input" type="button"></button>
</div>
<button id="btn-next" class="btn btn-next disable row" disabled>获取短信验证码</button>
</div>
</div>
\ No newline at end of file
... ...
<div class="sms-login passport-page yoho-page">
{{> passport/header}}
<div class="content">
<p class="sms-login-msg small">你以后还可以使用手机号码 + 密码的形式登录有货哦!</p>
<div class="input-container row has-eye">
<input id="pwd" class="pwd input" type="text" placeholder="密码">
<div class="eye" id="eye"></div>
</div>
<span id="btn-next" class="btn btn-next disable row">确定</span>
</div>
</div>
\ No newline at end of file
... ...
... ... @@ -11,6 +11,7 @@ const isTest = process.env.NODE_ENV === 'test';
module.exports = {
app: 'h5',
appVersion: '4.9.2', // 调用api的版本
port: 6001,
siteUrl: '//m.yohobuy.com',
assetUrl: '//localhost:5001',
... ... @@ -32,12 +33,11 @@ module.exports = {
activity: '//activity.yohobuy.com',
index: '//m.yohobuy.com'
},
useOneapm: false,
useCache: false,
memcache: {
master: ['192.168.102.205:12111'],
slave: ['192.168.102.205:12111'],
session: ['192.168.102.205:12111'],
master: ['192.168.102.168:12111'],
slave: ['192.168.102.168:12111'],
session: ['192.168.102.168:12111'],
timeout: 1000,
retries: 0
},
... ... @@ -90,13 +90,12 @@ if (isProduction) {
master: ['memcache1.yohoops.org:12111', 'memcache2.yohoops.org:12111', 'memcache3.yohoops.org:12111'],
slave: ['memcache1.yohoops.org:12112', 'memcache2.yohoops.org:12112', 'memcache3.yohoops.org:12112'],
session: ['memcache1.yohoops.org:12111', 'memcache2.yohoops.org:12111', 'memcache3.yohoops.org:12111'],
timeout: 1000,
timeout: 100,
retries: 0
},
useOneapm: true,
useCache: true,
interfaceShunt: {
open: true,
open: false,
url: 'http://123.206.2.55/strategy'
}
});
... ... @@ -105,18 +104,17 @@ if (isProduction) {
appName: 'm.yohobuy.com for test',
assetUrl: '//cdn.yoho.cn/m-yohobuy-node/assets',
domains: {
api: 'http://api-test3.yohops.com:9999/',
service: 'http://service-test3.yohops.com:9999/',
liveApi: 'http://testapi.live.yohops.com:9999/'
api: process.env.TEST_API || 'http://api-test1.yohops.com:9999/',
service: process.env.TEST_SERVICE || 'http://service-test1.yohops.com:9999/',
liveApi: process.env.TEST_LIVE || 'http://testapi.live.yohops.com:9999/'
},
memcache: {
master: ['127.0.0.1:12111'],
slave: ['127.0.0.1:12112'],
session: ['127.0.0.1:12111'],
timeout: 1000,
timeout: 100,
retries: 0
},
useOneapm: true,
useCache: true
});
}
... ...
... ... @@ -21,10 +21,16 @@ module.exports = () => {
// 判断请求是否来自app
yoho.isApp = req.query.app_version || req.query.appVersion;
yoho.isWechat = /micromessenger/i.test(req.get('User-Agent') || '');
Object.assign(res.locals, yoho);
Object.assign(req.yoho, yoho);
// App 内请求支持跨域
if (yoho.isApp) {
res.set('Access-Control-Allow-Origin', '*');
}
next();
};
};
... ...
... ... @@ -8,28 +8,6 @@ function async_load(){
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-W958MG');
(function() {
var hm = document.createElement("script");
hm.src = "//static.yohobuy.com/js/analytics/analysis.js";
hm.async = 1;
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
}
window.addEventListener('load', async_load, false);
</script>
<script>
window._py = window._py||[];
window._py.push(['a', 'MC..o8vMMWxEXDCiqYckD81lUX']);
window._py.push(['domain','stats.ipinyou.com']);
window._py.push(['e','']);
if(typeof _goodsData!='undefined'){
window._py.push(['pi',_goodsData]);
}
-function(d){
var f = 'https:' == d.location.protocol;var c = d.createElement('script');c.type='text/javascript';c.async=1;
c.src=(f ? 'https' : 'http') + '://'+(f?'fm.ipinyou.com':'fm.p0y.cn')+'/j/t/adv.js';
var h = d.getElementsByTagName("script")[0];h.parentNode.insertBefore(c, h);
}(document);
</script>
\ No newline at end of file
... ...
{{#data}}
<div class="banner-center">
<a href="{{url}}">
<img class="lazy" data-original="{{image src 640 200}}" alt="">
</a>
<div class="banner-center banner-center-swiper">
{{#if singleOne}}
{{#data}}
<div class="banner-list">
<a href="{{url}}">
<img src="{{image src 640 200}}" alt="">
</a>
</div>
{{/data}}
{{else}}
<ul class="banner-list swiper-wrapper clearfix">
{{#data}}
<li class="swiper-slide">
<a href="{{url}}">
<img src="{{image src 640 200}}" alt="">
</a>
</li>
{{/data}}
</ul>
{{/if}}
<div class="swiper-pagination">
<div class="pagination-inner">
</div>
</div>
{{/data}}
\ No newline at end of file
</div>
\ No newline at end of file
... ...
... ... @@ -5,7 +5,8 @@
<li class="brand">
<a href="{{url}}">
<div class="brand-logo">
<img class="lazy" data-original="{{image src 158 174}}">
{{!--此处不使用 Lazyload 是由于安卓 UC 10 版本加载不出来--}}
<img src="{{image src 158 174}}">
</div>
<p class="brand-name">{{name}}</p>
</a>
... ...
{
"name": "m-yohobuy-node",
"version": "4.9.12",
"version": "4.9.24",
"private": true,
"description": "A New Yohobuy Project With Express",
"repository": {
... ... @@ -45,7 +45,6 @@
"memcached": "^2.2.1",
"moment": "^2.14.1",
"morgan": "^1.7.0",
"oneapm": "^1.2.20",
"passport": "^0.3.2",
"passport-local": "^1.0.0",
"passport-qq": "0.0.3",
... ... @@ -57,7 +56,7 @@
"uuid": "^2.0.2",
"winston": "^2.2.0",
"winston-daily-rotate-file": "^1.2.0",
"yoho-node-lib": "0.0.46"
"yoho-node-lib": "0.0.49"
},
"devDependencies": {
"autoprefixer": "^6.3.7",
... ...