Authored by ccbikai

Merge branch 'feature/index' into develop

... ... @@ -40,7 +40,7 @@ const channelLogger = (err, res) => {
* @return {[type]}
*/
const channelPage = (req, res, data) => {
channelModel.getChannelDate({
channelModel.getChannelData({
gender: data.gender,
uid: _.toString(req.user.uid)
}).then(result => {
... ... @@ -53,9 +53,19 @@ const channelPage = (req, res, data) => {
/**
* 频道选择页
*/
// exports.index = (req, res) => {
//
// };
exports.index = (req, res) => {
channelModel.getChannelSwitchData().then((result) => {
res.render('index', {
module: 'channel',
page: 'index',
title: 'Yoho!Buy 有货',
searchUrl: helpers.urlFormat('/', null, 'search'),
pageFooter: true,
channelList: result[0],
background: result[1]
});
});
};
/**
* 频道页,根据查询字符串跳转频道中间件
... ... @@ -131,7 +141,7 @@ exports.lifestyle = (req, res) => {
exports.bottomBanner = (req, res) => {
let gender = req.query.gender || 'boys';
channelModel.getBottomBannerDate(gender).then(result => {
channelModel.getBottomBannerData(gender).then(result => {
res.send(result);
}).catch((err) => {
channelLogger(err, res);
... ...
... ... @@ -10,10 +10,15 @@ const _ = require('lodash');
const ServiceAPI = require(`${library}/api`).ServiceAPI;
const sign = require(`${library}/sign`);
const camelCase = require(`${library}/camel-case`);
const logger = require(`${library}/logger`);
const resourcesProcess = require(`${utils}/resources-process`);
const api = new ServiceAPI();
/**
* 性别数据
* @type {Object}
*/
const genderData = {
boys: '1,3',
girls: '2,3'
... ... @@ -27,7 +32,8 @@ const contentCode = {
boys: '8512bf0755cc549ac323f852c9fd945d',
girls: '189b6686065dbd6755dd6906cf03c002',
kids: 'b8c1bff53d4ea60f978926d538620636',
lifestyle: '61cd852c6afcf60660196154f66a3a62'
lifestyle: '61cd852c6afcf60660196154f66a3a62',
index: '7ba9118028f9b22090b57341487567eb'
};
/**
... ... @@ -40,6 +46,33 @@ const bottomBannerCode = {
};
/**
* 频道选择页 默认数据
* @type {Object}
*/
const channelList = {
1: {
href: '/boys',
title: '男生',
entitle: 'BOYS'
},
2: {
href: '/girls',
title: '女生',
entitle: 'GIRLS'
},
3: {
href: '/kids',
title: '潮童',
entitle: 'KIDS'
},
4: {
href: '/lifestyle',
title: '创意生活',
entitle: 'LIFESTYLE'
}
};
/**
* 获取二级菜单顶部颜色
* @param {[string]} choosed
* @return {[string]}
... ... @@ -111,10 +144,11 @@ const getChannelResource = (params) => {
params.new_device = true; // eslint-disable-line
}
return api.get('operations/api/v5/resource/home', sign.apiSign(params), 300).then(result => {
return api.get('operations/api/v5/resource/home', sign.apiSign(params), true).then(result => {
if (result && result.code === 200) {
return resourcesProcess(result.data.list);
} else {
logger.error('首页资源位接口返回状态码 不是 200');
return result;
}
});
... ... @@ -128,24 +162,84 @@ const getChannelResource = (params) => {
const getLeftNav = (choosed) => {
choosed = choosed || 'all';
return api.get('operations/api/v6/category/getCategory', sign.apiSign({}), 300).then(result => {
return api.get('operations/api/v6/category/getCategory', sign.apiSign({}), true).then(result => {
if (result && result.code === 200) {
return processSideBar(result.data, choosed);
} else {
logger.error('侧边栏数据接口返回状态码 不是 200');
return result;
}
});
};
/**
* 获取频道选择页数据
* @return {[type]}
*/
const getChannelList = () => {
return api.get('operations/api/v5/entrance/getEntrance', sign.apiSign({}), true).then((result) => {
if (result && result.code === 200) {
const list = {};
result.data.list = camelCase(result.data.list || []);
_.forEach(result.data.list, function(item) {
const channel = channelList[item.channelId];
if (channel) {
list[item.channelId] = channelList[item.channelId];
}
if (_.toNumber(item.channelId) === 5) {
list.showYohood = true;
list.yohoodHref = 'http://yohood.cn';
}
});
return Object.keys(list).length ? list : channelList;
} else {
logger.error('频道选择接口返回状态码 不是 200');
return channelList;
}
});
};
/**
* 获取频道选择页 背景
* @return {[type]}
*/
const getChannelBg = () => {
return api.get('operations/api/v5/resource/get', sign.apiSign({
content_code: contentCode.index
}), true).then(result => {
if (result && result.code === 200) {
return result.data.length && result.data[0] && result.data[0].data && result.data[0].data.list[0];
} else {
logger.error('频道选择页背景图接口返回状态码 不是 200');
return {
src: ''
};
}
});
};
/**
* 获取频道选择页面数据
* @param {[string]} gender
* @return {[type]}
*/
exports.getChannelSwitchData = () => {
return Promise.all([getChannelList(), getChannelBg()]);
};
/**
* 获取频道页面数据
* @param {[object]} params
* @return {[object]}
*/
exports.getChannelDate = (params) => {
exports.getChannelData = (params) => {
var channelData = {};
return api.all([getChannelResource(params), getLeftNav(params.gender)]).then((data) => {
return Promise.all([getChannelResource(params), getLeftNav(params.gender)]).then((data) => {
channelData.content = data[0]; // 资源位数据
channelData.sideNav = data[1]; // 侧边栏数据
... ... @@ -158,13 +252,13 @@ exports.getChannelDate = (params) => {
* @param {[string]} gender
* @return {[type]}
*/
exports.getBottomBannerDate = (gender) => {
exports.getBottomBannerData = (gender) => {
gender = gender || 'boys';
if (gender === 'boys' || gender === 'girls') {
return api.get('operations/api/v5/resource/get', sign.apiSign({
content_code: bottomBannerCode[gender] // eslint-disable-line
}));
}), true);
}
return Promise.resolve({
code: 400,
... ...
... ... @@ -12,6 +12,7 @@ const channel = require(cRoot);
const router = express.Router(); // eslint-disable-line
router.get('/', channel.switchChannel, channel.index); // 首页,频道选择页
router.get('/boys', channel.switchChannel, channel.boys);
router.get('/girls', channel.switchChannel, channel.girls);
router.get('/kids', channel.switchChannel, channel.kids);
... ...
<div class="index-page yoho-page">
<div class="index-container">
<div class="index-header clearfix">
<div class="index-logo">
</div>
<div class="box">
<a href="javascript:void(0);" class="no-search">取消</a>
<form action="{{searchUrl}}" class="index-search">
<div class="search-box">
<input type="hidden" name="from" value="search">
<input type="text" name="query" placeholder="搜索" autocomplete="off">
<span class="iconfont clear-text">&#xe623;</span>
<span class="iconfont search-icon empty">&#xe60f;</span>
</div>
</form>
</div>
</div>
<div class="index-channel">
<img class="img" src="{{image background.src 640 800}}">
<div class="index-channel-list">
{{#each channelList}}
<a href="{{href}}" class="list-item">
{{title}} <span class="lighter">{{entitle}}</span>
<span class="iconfont right-icon">&#xe614;</span>
</a>
{{/each}}
{{#showYohood}}
<a href="{{yohoodHref}}" id="yohood" class="list-item"> <span class="iconfont right-icon">&#xe614;</span></a>
{{/showYohood}}
</div>
</div>
</div>
</div>
... ...
/**
* 频道选择页面顶部搜索
* @author: bikai<kai.bi@yoho.cn>
* @date: 2015/10/28
*/
var $ = require('yoho-jquery'),
security = require('../plugin/security');
var $searchBox = $('.search-box'),
$box = $('.box'),
$indexSearch = $('.index-search'),
$indexLogo = $('.index-logo'),
$channelLink = $('.index-channel a:not(#yohood)');
var $search = $searchBox.children('input[type="text"]'),
$cancelSearch = $box.children('.no-search'),
$searchIcon = $searchBox.children('.search-icon');
require('../common');
$search.on('focus', function() {
$box.addClass('action');
$indexLogo.addClass('action');
}).on('input', function() {
if ($search.val() === '') {
$searchIcon.addClass('empty');
} else {
$searchIcon.removeClass('empty');
}
});
$cancelSearch.on('touchend', function() {
$box.removeClass('action');
$indexLogo.removeClass('action');
$search.blur();
return false;
});
$searchBox.children('.clear-text').on('touchstart', function() {
$search.val('').focus().trigger('input');
});
$searchBox.children('.search-icon').on('touchstart', function() {
if (security.hasDangerInput()) {
return false;
}
$indexSearch.submit();
});
$searchBox.keyup(function(e) {
if (e.keyCode === 13) {
if (security.hasDangerInput()) {
return false;
}
$indexSearch.submit();
}
});
$('.index-channel img').on('load error', function() {
window.rePosFooter && window.rePosFooter();
});
$channelLink.on('touchstart', function() {
$channelLink.css({
background: '#000',
color: '#fff',
borderColor: '#fff'
});
$(this).css({
background: 'rgba(255, 255, 255, 0.5)',
color: '#000',
borderColor: '#000'
});
}).on('touchend touchcancel', function() {
$(this).css({
background: '#000',
color: '#fff',
borderColor: '#fff'
});
});
... ...
/**
* 校验input, 防止SQL注入
* @author: 赵彪<bill.zhao@yoho.cn>
* @date: 2015/11/30
*/
var $ = require('yoho-jquery'),
tip = require('./tip');
/**
* hasStrangeInput() return true when input have danger value
*
* @param {Bool} needConvert Set if the danger input value should be converted to space
* @return {Bool} true/false If the input have danger value
*/
function hasDangerInput(needConvert) {
var $inputs = $('input[type!=hidden], textarea');
var validationPartten = /['"<>&\|]|--/g,
inputsLength = $inputs.length,
val,
i,
matchChars,
// to set if the input value should be coverted, and its default value is true;
willConvert = typeof needConvert === 'undefined' || typeof needConvert !== 'boolean' ? true : needConvert;
for (i = 0; i < inputsLength; i++) {
val = $inputs.eq(i).val();
if (validationPartten.test(val)) {
if (willConvert) {
$inputs.eq(i).val(val.replace(validationPartten, ' '));
} else {
matchChars = val.match(validationPartten).join(' ');
tip.show('不可以输入 ' + matchChars + ' 哦!');
}
return !willConvert && true;
}
}
return false;
}
exports.hasDangerInput = hasDangerInput;
... ...
@import "header-download";
@import "banner-top";
@import "banner-center";
@import "banner-bottom";
@import "side-nav";
@import "floor-header";
@import "footer-tab";
@import "hot-brands";
@import "fine-brands";
@import "creative-life";
@import "plus-star";
@import "maybe-like";
@import "icons-enter";
@import "trendsetter-collocation";
@import "trend-topics";
@import "goods-category";
@import "hot-brands";
@import "hot-category";
@import "home-header";
@import "thumb-row";
@import "notice";
@import "fresh-only";
@import "coupon";
.mobile-container {
margin-left: auto;
margin-right: auto;
width: 100%;
max-width: 640px;
overflow: hidden;
}
.mobile-wrap {
position: relative;
z-index: 2;
background: #f0f0f0;
transition: transform 0.3s;
}
.mobile-wrap.menu-open {
transform: translateX(540px);
}
.overlay {
display: none;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #000;
z-index: 4;
transition: opacity 1s;
}
.overlay.show {
display: block;
opacity: 0.3;
}
... ...
@import "header-download";
@import "banner-top";
@import "banner-center";
@import "banner-bottom";
@import "side-nav";
@import "floor-header";
@import "footer-tab";
@import "hot-brands";
@import "fine-brands";
@import "creative-life";
@import "plus-star";
@import "maybe-like";
@import "icons-enter";
@import "trendsetter-collocation";
@import "trend-topics";
@import "goods-category";
@import "hot-brands";
@import "hot-category";
@import "home-header";
@import "thumb-row";
@import "notice";
@import "fresh-only";
@import "coupon";
.mobile-container {
margin-left: auto;
margin-right: auto;
width: 100%;
max-width: 640px;
.index-page {
overflow: hidden;
}
margin: 0 auto;
width: 100%;
.mobile-wrap {
position: relative;
z-index: 2;
background: #f0f0f0;
transition: transform 0.3s;
}
#yohood {
border: none;
border-bottom: 4PX solid #fff;
background-color: transparent;
background-image: resolve('channel/yohood.png');
background-position-x: 26%;
background-position-y: 36%;
background-size: 40%;
background-repeat: no-repeat;
}
.mobile-wrap.menu-open {
transform: translateX(540px);
}
#yohood:active {
border-bottom-color: #000;
background-color: rgba(255, 255, 255, 0.4);
background-image: resolve('channel/yohood-tapped.png');
.overlay {
display: none;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #000;
z-index: 4;
transition: opacity 1s;
}
.right-icon {
color: #000;
}
}
.index-header {
box-sizing: border-box;
padding: 0 20px;
width: 100%;
height: 96px;
line-height: 96px;
.index-logo {
float: left;
width: 288px;
height: 96px;
background: resolve("channel/yohologo.png") left center no-repeat;
background-size: 280px 60px;
opacity: 1;
transition: all 400ms;
img {
width: 207px;
height: 49px;
vertical-align: middle;
}
&.action {
width: 0;
opacity: 0;
}
}
.box {
position: relative;
z-index: 1;
overflow: hidden;
&.action {
.no-search,
.clear-text {
display: block;
}
}
}
.index-search {
overflow: hidden;
height: 96px;
background: #fff;
transition: width 0.4s;
.search-box {
position: relative;
top: 20px;
overflow: hidden;
box-sizing: border-box;
padding-right: 80px;
height: 56px;
border: 1px solid #ccc;
transition: width 400ms;
transition: margin-left 0.4s;
}
.overlay.show {
display: block;
opacity: 0.3;
input {
float: left;
overflow: hidden;
padding: 10px;
width: 96%;
border: none;
color: #999;
font-size: 28px;
-webkit-appearance: none;
}
.iconfont {
position: absolute;
top: 8px;
z-index: 1;
width: 40px;
font-size: 28px;
line-height: 40px;
}
.clear-text {
right: 50px;
display: none;
color: #ccc;
}
.search-icon {
right: 10px;
color: #666;
&.empty {
color: #e6e6e6;
}
}
}
.no-search {
display: none;
float: left;
margin-right: 10px;
color: #999;
font-size: 28px;
}
}
.index-container {
position: relative;
background-color: white;
transition: transform 0.5s;
.index-channel {
position: relative;
min-height: 800px;
background-color: #000;
color: #fff;
text-align: center;
.index-channel-list {
position: absolute;
top: 50%;
margin-top: -300px;
width: 100%;
.list-item {
position: relative;
display: block;
margin: 0 auto 40px;
width: 432px;
height: 104px;
border: 4PX solid #fff;
background-color: #000;
color: #fff;
text-align: center;
font-weight: bold;
font-size: 32px;
line-height: 104px;
}
.list-item:last-child {
margin-bottom: 0;
}
.lighter {
font-weight: lighter;
}
.right-icon {
position: absolute;
top: 0;
right: 10px;
font-weight: bold;
}
.homestyle {
margin-bottom: 50px;
width: 287.3px;
}
}
}
}
}
@@import "home" ;
... ...