Authored by 沈志敏

Merge branch 'develop' of git.yoho.cn:fe/yohoblk-wap into develop

... ... @@ -9,18 +9,19 @@ const channelModel = require('../models/channel');
/**
* 频道选择页
*/
const channel = {
module.exports = {
index(req, res) {
let channel = req.path.split('/')[1] || req.yoho.channel;
res.render('index', {
module: 'channel',
page: 'home'
page: 'home',
channel: channel
});
},
resources(req, res, next) {
channelModel.getResourcesData(req.yoho.channel).then(result => {
channelModel.getResourcesData(req.query).then(result => {
return res.json(result);
}).catch(next);
}
};
module.exports = channel;
... ...
... ... @@ -4,9 +4,18 @@ const contentCode = require('../../../config/content-code');
const resourcesProcess = require('../../../utils/resources-process');
let channel = {
getResourcesData(c) {
getResourcesData(params) {
let code;
if (params.channel) {
code = contentCode.channel[params.channel];
} else if (params.contentCode) {
code = params.contentCode;
} else {
code = contentCode.channel.men;
}
return api.get('operations/api/v5/resource/get', {
content_code: contentCode.channel[c]
content_code: code
}, {
cache: true,
code: 200
... ...
... ... @@ -13,6 +13,9 @@ const channel = require(cRoot + '/channel');
const router = expressRouter();
router.get('/', channel.index); // 首页
router.get('/men', channel.index); // 首页
router.get('/women', channel.index); // 首页
router.get('/lifestyle', channel.index); // 首页
router.get('/resources', channel.resources); // 资源位接口
module.exports = router;
... ...
<div id="app">
<tab></tab>
<resources></resources>
<resources v-bind:channel="'{{channel}}'" v-ref:resources></resources>
</div>
... ...
/**
* 商品列表页
* @author chen xuan <xuan.chen@yoho.cn>
*/
const listModel = require('../models/list');
exports.index = (req, res) =>{
res.render('list');
};
/*
* 获取 商品列表
*/
exports.getProducts = (req, res, next)=>{
listModel.search()
.then(data=>{
res.json(data);
})
.catch(next);
};
... ...
/**
* sub app product
* @author: chen xuan<xuan.chen@yoho.cn>
* @date: 2016/07/19
*/
var express = require('express'),
path = require('path'),
hbs = require('express-handlebars');
var app = express();
// set view engin
var doraemon = path.join(__dirname, '../../doraemon/views'); // parent view root
app.on('mount', function(parent) {
delete parent.locals.settings; // 不继承父 App 的设置
Object.assign(app.locals, parent.locals);
});
app.set('views', path.join(__dirname, 'views/action'));
app.engine('.hbs', hbs({
extname: '.hbs',
defaultLayout: 'layout',
layoutsDir: doraemon,
partialsDir: [path.join(__dirname, 'views/partial'), `${doraemon}/partial`],
helpers: global.yoho.helpers
}));
// router
app.use(require('./router'));
module.exports = app;
... ...
/**
* product list Model
*/
'use strict';
const api = global.yoho.API;
const camelCase = global.yoho.camelCase;
const path = require('path');
const processProductList = require(path.join(global.utils, '/product-process')).processProductList;
let list = {
/**
* 商品搜索
* @param {[type]} params [description]
* @return {[type]} [description]
*/
search(params) {
return api.post('', {
method: 'app.search.sales',
limit: 4,
saleType: 2,
yh_channel: 3
}, {
cache: true,
code: 200
})
.then(result => {
result = camelCase(result);
result.data.productList = processProductList(result.data.productList);
return result;
});
}
};
module.exports = list;
... ...
/**
* router of sub app product
* @author: chen xuan<xuan.chen@yoho.cn>
* @date: 2016/07/19
*/
'use strict';
const Router = require('express').Router;
const cRoot = './controllers';
const productList = require(`${cRoot}/list`);
const router = Router();
// 商品列表
router.use('/list', (req, res, next) => {
req.module = 'product';
req.page = 'list';
next();
});
router.get('/list', productList.index);
router.post('/list', productList.getProducts);
module.exports = router;
... ...
<div id="product-list">
<Sort></Sort>
<List url="/product/list" :query='{a:1}'></List>
</div>
\ No newline at end of file
... ...
... ... @@ -7,7 +7,9 @@
'use strict';
const channel = {
men: '9ee58aadd9559d07207fe4a98843eaac'
men: '9ee58aadd9559d07207fe4a98843eaac', // 男 9ee58aadd9559d07207fe4a98843eaac
women: '9ee58aadd9559d07207fe4a98843eaac',
lifestyle: '9ee58aadd9559d07207fe4a98843eaac'
};
module.exports = {
... ...
... ... @@ -6,6 +6,7 @@
module.exports = app => {
app.use('/', require('./apps/channel'));
app.use('/product', require('./apps/product'));
app.use('/home', require('./apps/home'));
// 组件示例
... ...
... ... @@ -57,6 +57,7 @@
"handlebars": "^4.0.5",
"handlebars-loader": "^1.3.0",
"husky": "^0.11.4",
"node-sass": "^3.8.0",
"nodemon": "1.9.2",
"postcss-assets": "^4.0.1",
"postcss-cachebuster": "^0.1.3",
... ... @@ -70,6 +71,7 @@
"postcss-sprites": "^3.1.2",
"postcss-use": "^2.2.0",
"precss": "^1.4.0",
"sass-loader": "^4.0.0",
"shelljs": "^0.7.0",
"style-loader": "^0.13.1",
"stylelint": "^6.9.0",
... ...
... ... @@ -2,10 +2,17 @@ const Vue = require('yoho-vue');
const tab = require('channel/tab.vue');
const resources = require('channel/resources.vue');
require('common/vue-filter');
new Vue({
el: '#app',
components: {
tab: tab,
resources: resources
},
created() {
this.$on('changeChannel', channel => {
this.$refs.resources.channel = channel;
});
}
});
... ...
let Vue = require('yoho-vue');
/**
* 替换参数
*
* @example
* value = /{width}/{height}/{model}
*
* {value | resize 100 200 2} ==> /100/200/2
*/
Vue.filter('resize', (value, width, height, model)=>{
return value.replace(/({width}|{height}|{mode})/g, function($0) {
const dict = {
'{width}': width,
'{height}': height,
'{mode}': model || 2
};
return dict[$0];
});
});
... ...
const Vue = require('yoho-vue');
const Sort = require('component/sort.vue');
const List = require('component/list.vue');
new Vue({
el: '#product-list',
components: {
List, Sort
}
});
... ...
<template>
<div class="resources">
<template v-for="floor in resources">
<div class="focus" v-if="floor.focus">
<focus :list="floor.data"></focus>
</div>
<div class="title-image" v-if="floor.titleImage">
<title-image></title-image>
</div>
<focus v-if="floor.focus" v-bind:floor="floor.data" v-bind:style="{height: '182px'}"></focus>
<title-image v-if="floor.titleImage" v-bind:floor="floor.data"></title-image>
<goods v-if="floor.goods" v-bind:floor="floor.data"></goods>
</template>
</div>
</template>
... ... @@ -16,8 +13,12 @@
const tip = require('common/tip');
const focus = require('component/resources/focus.vue');
const titleImage = require('component/resources/title-image.vue');
const goods = require('component/resources/goods.vue');
const Loading = require('common/loading');
const loading = new Loading();
module.exports = {
props: ['channel', 'contentCode'],
data() {
return {
resources: []
... ... @@ -25,20 +26,47 @@
},
components: {
focus: focus,
titleImage: titleImage
titleImage: titleImage,
goods: goods
},
init() {
$.ajax({
url: '/resources'
}).then(result => {
this.resources = result;
}).fail(() => {
tip('网络错误');
});
watch: {
channel() {
this.getResourcesData();
},
contentCode() {
this.getResourcesData();
}
},
methods: {
getResourcesData() {
let data = {};
if (this.contentCode) {
data.contentCode = this.contentCode;
} else {
data.channel = this.channel;
}
loading.show();
$.ajax({
url: '/resources',
data: data
}).then(result => {
this.resources = result;
loading.hide();
}).fail(() => {
tip('网络错误');
});
}
},
created() {
this.getResourcesData();
}
};
</script>
<style>
.resources {
background: #f6f6f6;
}
</style>
... ...
<template>
<div class="channel-tab">
<a v-for="(index, item) in channel" v-bind:class="{focus: index === current}" v-on:click.prevent="changeChannel(index)" href="{{item.url}}">
<a v-for="(index, item) in channel" v-bind:class="{focus: index === current}" v-on:click.prevent="changeChannel(index)" href="/{{item.channel}}">
<span class="name">{{item.name | uppercase}}</span>
</a>
</div>
... ... @@ -13,33 +13,32 @@
current: 0,
channel: [{
name: 'MEN男士',
url: '/men'
channel: 'men'
}, {
name: 'WOMEN女士',
url: '/women'
channel: 'women'
}, {
name: 'LIFESTYLE生活',
url: '/lifestyle'
channel: 'lifestyle'
}]
};
},
methods: {
changeChannel(index) {
this.current = index;
this.$parent.$emit('changeChannel', this.channel[index].channel);
}
}
};
</script>
<style>
@import "../../scss/common/color";
.channel-tab {
width: 100%;
height: 90px;
font-size: 24px;
text-align: center;
background: $white;
background: #fff;
a {
display: inline-block;
... ... @@ -48,7 +47,7 @@
color: #999;
&.focus {
color: $black;
color: #000;
}
}
... ... @@ -56,13 +55,13 @@
padding: 9px 0;
&.focus {
border-bottom: 4px solid $black;
border-bottom: 4px solid #000;
}
}
.focus {
.name {
border-bottom: 4px solid $black;
border-bottom: 4px solid #000;
}
}
}
... ...
<template>
<div class="goods-box">
<ul class="cardlist card-large">
<li class="card" v-for="item in items">
<div class="card-pic">
<a href="">
<img :src="item.img" alt="{{item.name}}">
</a>
</div>
<div class="card-bd">
<h2 class="card-label">
<a href="">{{item.label}}</a>
</h2>
<span class="good-price" :class="{'old-price': item.market_price}" v-if="item.market_price">¥ {{item.market_price}}</span>
<span class="good-price" :class="{'sale-price': item.market_price}">¥ {{item.sale_price}}</span>
</div>
</li>
</ul>
</div>
</template>
<script>
let $ = require('yoho-jquery');
module.exports = {
props: {
//请求 地址
url: {
type: String,
required: true
},
//请求参数
query: Object
},
data: function() {
return {
items: []
}
},
methods: {
fetch: function() {
$.ajax({
url: this.url,
type: 'POST',
})
.then(data=>{
console.log(data)
})
}
},
ready: function() {
this.fetch()
},
}
</script>
<style>
@import '../../scss/common/color';
.cardlist {
list-style: none;
margin: 0;
padding: 0;
}
.card-large {
.card {
float: left;
width: 372px;
margin-right: 6px;
&:nth-child(2n) {
margin-right: 0;
}
;
}
.card-pic {
width: 100%;
height: 499px;
a,
img {
display: block;
width: 100%;
height: 100%;
}
}
.card-bd {
min-height: 180px;
margin-left: 30px;
margin-right: 30px;
padding-top: 25px;
text-align: center;
font-size: 24px;
}
.card-label {
margin: 0 0 10px 0;
font-size: inherit;
font-weight: normal;
}
}
.good-price {
color: #b0b0b0;
margin-right: 10px;
&:last-of-type {
margin-right: 0;
}
&.old-price {
text-decoration: line-through;
}
&.sale-price {
color: $red;
}
}
</style>
... ...
<template>
<div class="floor-header">
{{title.title}}
<a class="more" href="{{title.moreUrl}}">
{{title.moreName}}
</a>
</div>
</template>
<script>
module.exports = {
props: ['title']
};
</script>
<style>
.floor-header {
position: relative;
width: 100%;
height: 100px;
font-size: 32px;
line-height: 100px;
text-align: center;
font-weight: bold;
border-top: 1px solid #eee;
margin-top: 20px;
background: #fff;
.more {
position: absolute;
top: 0;
right: 0;
width: 100px;
height: 100px;
}
}
</style>
... ...
<template>
<swipe class="my-swipe">
<swipe-item v-for="item in list" class="aaaa">
<a href="{{item.url}}" title="{{item.title}}">
<img src="{{item.src}}">
</a>
</swipe-item>
</swipe>
<div class="focus">
<swipe class="swipe swipe-{{floor.length}}">
<swipe-item v-for="item in floor" v-bind:style="{backgroundColor: item.bgColor}">
<a href="{{item.url}}" title="{{item.title}}">
<img v-bind:src="item.src | resize 750 365">
</a>
</swipe-item>
</swipe>
</div>
</template>
<script>
... ... @@ -13,7 +15,7 @@
const swipe = require('vue-swipe');
module.exports = {
props: ['list'],
props: ['floor'],
components: {
swipe: swipe.Swipe,
swipeItem: swipe.SwipeItem
... ... @@ -22,5 +24,43 @@
</script>
<style>
.focus {
.swipe {
height: 100%;
}
.swipe-1 {
.swipe-indicators {
display: none;
}
}
.swipe-item {
a {
display: block;
}
img {
width: 100%;
height: 100%;
}
}
.swipe-indicators {
left: initial;
right: 20px;
}
.swipe-indicator {
width: 8px;
height: 8px;
background: #ccc;
opacity: 1;
&.active {
width: 12px;
height: 12px;
background: #fff;
}
}
}
</style>
... ...
<template>
<div class="goods">
goods
</div>
</template>
<script>
const floorHeader = require('component/resources/floor-header.vue');
module.exports = {
props: ['floor'],
components: {
floorHeader: floorHeader
}
};
</script>
<style>
</style>
... ...
<template>
<div class="focus">
title-image
<div class="title-image">
<floor-header v-bind:title="floor.title"></floor-header>
<a class="image" v-bind:href="floor.image.url">
<img v-bind:src="floor.image.src | resize 750 364">
</a>
</div>
</template>
<script>
const floorHeader = require('component/resources/floor-header.vue');
module.exports = {
data() {
return {
message: 'resources'
};
props: ['floor'],
components: {
floorHeader: floorHeader
}
};
</script>
<style>
.title-image {
a {
display: block;
}
.image {
width: 100%;
height: 364px;
}
img {
width: 100%;
height: 100%;
}
}
</style>
... ...
<template>
<ul class="sort-navs clearfix">
<li class="sort-item active"><span>默认</span></li>
<li class="sort-item">
<span class="sort-name">最新</span>
</li>
<li class="sort-item">
<span class="sort-name">价格</span>
</li>
<li class="sort-item">
<span class="sort-name">折扣</span>
</li>
</ul>
</template>
<script>
module.exports = {
}
</script>
<style>
@import '../../scss/common/color';
.sort-navs {
list-style: none;
margin: 0;
padding: 25px 0;
color: $grey;
}
.sort-item {
position: relative;
display: block;
width: 25%;
float: left;
text-align: center;
&:after {
content: '|';
position: absolute;
right: 0;
color: $grey;
font-size: 28px;
}
&:last-of-type:after {
display: none;
}
.sort-name {
font-size: 28px;
}
&.active {
color: $black;
}
}
</style>
... ...