Showing
12 changed files
with
320 additions
and
0 deletions
apps/product/controllers/list.js
0 → 100644
1 | +/** | ||
2 | + * 商品列表页 | ||
3 | + * @author chen xuan <xuan.chen@yoho.cn> | ||
4 | + */ | ||
5 | +const listModel = require('../models/list'); | ||
6 | + | ||
7 | +exports.index = (req, res) =>{ | ||
8 | + res.render('list'); | ||
9 | +}; | ||
10 | + | ||
11 | +/* | ||
12 | + * 获取 商品列表 | ||
13 | + */ | ||
14 | +exports.getProducts = (req, res, next)=>{ | ||
15 | + listModel.search() | ||
16 | + .then(data=>{ | ||
17 | + res.json(data); | ||
18 | + }) | ||
19 | + .catch(next); | ||
20 | +}; |
apps/product/index.js
0 → 100644
1 | +/** | ||
2 | + * sub app product | ||
3 | + * @author: chen xuan<xuan.chen@yoho.cn> | ||
4 | + * @date: 2016/07/19 | ||
5 | + */ | ||
6 | + | ||
7 | +var express = require('express'), | ||
8 | + path = require('path'), | ||
9 | + hbs = require('express-handlebars'); | ||
10 | + | ||
11 | +var app = express(); | ||
12 | + | ||
13 | +// set view engin | ||
14 | +var doraemon = path.join(__dirname, '../../doraemon/views'); // parent view root | ||
15 | + | ||
16 | +app.on('mount', function(parent) { | ||
17 | + delete parent.locals.settings; // 不继承父 App 的设置 | ||
18 | + Object.assign(app.locals, parent.locals); | ||
19 | +}); | ||
20 | + | ||
21 | +app.set('views', path.join(__dirname, 'views/action')); | ||
22 | +app.engine('.hbs', hbs({ | ||
23 | + extname: '.hbs', | ||
24 | + defaultLayout: 'layout', | ||
25 | + layoutsDir: doraemon, | ||
26 | + partialsDir: [path.join(__dirname, 'views/partial'), `${doraemon}/partial`], | ||
27 | + helpers: global.yoho.helpers | ||
28 | +})); | ||
29 | + | ||
30 | +// router | ||
31 | +app.use(require('./router')); | ||
32 | + | ||
33 | +module.exports = app; |
apps/product/models/list.js
0 → 100644
1 | +/** | ||
2 | + * product list Model | ||
3 | + */ | ||
4 | +'use strict'; | ||
5 | +const api = global.yoho.API; | ||
6 | +const camelCase = global.yoho.camelCase; | ||
7 | +const path = require('path'); | ||
8 | +const processProductList = require(path.join(global.utils, '/product-process')).processProductList; | ||
9 | + | ||
10 | + | ||
11 | +let list = { | ||
12 | + | ||
13 | + /** | ||
14 | + * 商品搜索 | ||
15 | + * @param {[type]} params [description] | ||
16 | + * @return {[type]} [description] | ||
17 | + */ | ||
18 | + search(params) { | ||
19 | + return api.post('', { | ||
20 | + method: 'app.search.sales', | ||
21 | + limit: 4, | ||
22 | + saleType: 2, | ||
23 | + yh_channel: 3 | ||
24 | + }, { | ||
25 | + cache: true, | ||
26 | + code: 200 | ||
27 | + }) | ||
28 | + .then(result => { | ||
29 | + result = camelCase(result); | ||
30 | + result.data.productList = processProductList(result.data.productList); | ||
31 | + return result; | ||
32 | + }); | ||
33 | + } | ||
34 | +}; | ||
35 | + | ||
36 | + | ||
37 | +module.exports = list; |
apps/product/router.js
0 → 100644
1 | +/** | ||
2 | + * router of sub app product | ||
3 | + * @author: chen xuan<xuan.chen@yoho.cn> | ||
4 | + * @date: 2016/07/19 | ||
5 | + */ | ||
6 | + | ||
7 | +'use strict'; | ||
8 | + | ||
9 | +const Router = require('express').Router; | ||
10 | +const cRoot = './controllers'; | ||
11 | +const productList = require(`${cRoot}/list`); | ||
12 | + | ||
13 | +const router = Router(); | ||
14 | +// 商品列表 | ||
15 | +router.use('/list', (req, res, next) => { | ||
16 | + req.module = 'product'; | ||
17 | + req.page = 'list'; | ||
18 | + next(); | ||
19 | +}); | ||
20 | +router.get('/list', productList.index); | ||
21 | +router.post('/list', productList.getProducts); | ||
22 | + | ||
23 | +module.exports = router; |
apps/product/views/action/list.hbs
0 → 100644
@@ -6,6 +6,7 @@ | @@ -6,6 +6,7 @@ | ||
6 | 6 | ||
7 | module.exports = app => { | 7 | module.exports = app => { |
8 | app.use('/', require('./apps/channel')); | 8 | app.use('/', require('./apps/channel')); |
9 | + app.use('/product', require('./apps/product')); | ||
9 | 10 | ||
10 | // 组件示例 | 11 | // 组件示例 |
11 | if (app.locals.devEnv) { | 12 | if (app.locals.devEnv) { |
@@ -57,6 +57,7 @@ | @@ -57,6 +57,7 @@ | ||
57 | "handlebars": "^4.0.5", | 57 | "handlebars": "^4.0.5", |
58 | "handlebars-loader": "^1.3.0", | 58 | "handlebars-loader": "^1.3.0", |
59 | "husky": "^0.11.4", | 59 | "husky": "^0.11.4", |
60 | + "node-sass": "^3.8.0", | ||
60 | "nodemon": "1.9.2", | 61 | "nodemon": "1.9.2", |
61 | "postcss-assets": "^4.0.1", | 62 | "postcss-assets": "^4.0.1", |
62 | "postcss-cachebuster": "^0.1.3", | 63 | "postcss-cachebuster": "^0.1.3", |
@@ -70,6 +71,7 @@ | @@ -70,6 +71,7 @@ | ||
70 | "postcss-sprites": "^3.1.2", | 71 | "postcss-sprites": "^3.1.2", |
71 | "postcss-use": "^2.2.0", | 72 | "postcss-use": "^2.2.0", |
72 | "precss": "^1.4.0", | 73 | "precss": "^1.4.0", |
74 | + "sass-loader": "^4.0.0", | ||
73 | "shelljs": "^0.7.0", | 75 | "shelljs": "^0.7.0", |
74 | "style-loader": "^0.13.1", | 76 | "style-loader": "^0.13.1", |
75 | "stylelint": "^6.9.0", | 77 | "stylelint": "^6.9.0", |
public/js/common/vue-filter.js
0 → 100644
1 | +let Vue = require('yoho-vue'); | ||
2 | + | ||
3 | + | ||
4 | +/** | ||
5 | + * 替换参数 | ||
6 | + * | ||
7 | + * @example | ||
8 | + * value = /{width}/{height}/{model} | ||
9 | + * | ||
10 | + * {value | resize 100 200 2} ==> /100/200/2 | ||
11 | + */ | ||
12 | +Vue.filter('resize', (value, width, height, model)=>{ | ||
13 | + return value.replace(/({width}|{height}|{mode})/g, function($0) { | ||
14 | + const dict = { | ||
15 | + '{width}': width, | ||
16 | + '{height}': height, | ||
17 | + '{model}': model || 2 | ||
18 | + }; | ||
19 | + | ||
20 | + return dict[$0]; | ||
21 | + }); | ||
22 | +}); |
public/js/product/list.page.js
0 → 100644
public/vue/component/list.vue
0 → 100644
1 | +<template> | ||
2 | + <div class="goods-box"> | ||
3 | + <ul class="cardlist card-large"> | ||
4 | + <li class="card" v-for="item in items"> | ||
5 | + <div class="card-pic"> | ||
6 | + <a href=""> | ||
7 | + <img :src="item.img" alt="{{item.name}}"> | ||
8 | + </a> | ||
9 | + </div> | ||
10 | + <div class="card-bd"> | ||
11 | + <h2 class="card-label"> | ||
12 | + <a href="">{{item.label}}</a> | ||
13 | + </h2> | ||
14 | + <span class="good-price" :class="{'old-price': item.market_price}" v-if="item.market_price">¥ {{item.market_price}}</span> | ||
15 | + <span class="good-price" :class="{'sale-price': item.market_price}">¥ {{item.sale_price}}</span> | ||
16 | + </div> | ||
17 | + </li> | ||
18 | + </ul> | ||
19 | + </div> | ||
20 | +</template> | ||
21 | +<script> | ||
22 | +let $ = require('yoho-jquery'); | ||
23 | + | ||
24 | +module.exports = { | ||
25 | + props: { | ||
26 | + //请求 地址 | ||
27 | + url: { | ||
28 | + type: String, | ||
29 | + required: true | ||
30 | + }, | ||
31 | + //请求参数 | ||
32 | + query: Object | ||
33 | + }, | ||
34 | + data: function() { | ||
35 | + return { | ||
36 | + items: [] | ||
37 | + } | ||
38 | + }, | ||
39 | + methods: { | ||
40 | + fetch: function() { | ||
41 | + $.ajax({ | ||
42 | + url: this.url, | ||
43 | + type: 'POST', | ||
44 | + }) | ||
45 | + .then(data=>{ | ||
46 | + console.log(data) | ||
47 | + }) | ||
48 | + } | ||
49 | + }, | ||
50 | + ready: function() { | ||
51 | + this.fetch() | ||
52 | + }, | ||
53 | + | ||
54 | +} | ||
55 | +</script> | ||
56 | +<style> | ||
57 | +@import '../../scss/common/color'; | ||
58 | +.cardlist { | ||
59 | + list-style: none; | ||
60 | + margin: 0; | ||
61 | + padding: 0; | ||
62 | +} | ||
63 | + | ||
64 | +.card-large { | ||
65 | + .card { | ||
66 | + float: left; | ||
67 | + width: 372px; | ||
68 | + margin-right: 6px; | ||
69 | + &:nth-child(2n) { | ||
70 | + margin-right: 0; | ||
71 | + } | ||
72 | + ; | ||
73 | + } | ||
74 | + .card-pic { | ||
75 | + width: 100%; | ||
76 | + height: 499px; | ||
77 | + a, | ||
78 | + img { | ||
79 | + display: block; | ||
80 | + width: 100%; | ||
81 | + height: 100%; | ||
82 | + } | ||
83 | + } | ||
84 | + .card-bd { | ||
85 | + min-height: 180px; | ||
86 | + margin-left: 30px; | ||
87 | + margin-right: 30px; | ||
88 | + padding-top: 25px; | ||
89 | + text-align: center; | ||
90 | + font-size: 24px; | ||
91 | + } | ||
92 | + .card-label { | ||
93 | + margin: 0 0 10px 0; | ||
94 | + font-size: inherit; | ||
95 | + font-weight: normal; | ||
96 | + } | ||
97 | +} | ||
98 | + | ||
99 | +.good-price { | ||
100 | + color: #b0b0b0; | ||
101 | + margin-right: 10px; | ||
102 | + &:last-of-type { | ||
103 | + margin-right: 0; | ||
104 | + } | ||
105 | + &.old-price { | ||
106 | + text-decoration: line-through; | ||
107 | + } | ||
108 | + &.sale-price { | ||
109 | + color: $red; | ||
110 | + } | ||
111 | +} | ||
112 | +</style> |
public/vue/component/sort.vue
0 → 100644
1 | +<template> | ||
2 | + <ul class="sort-navs clearfix"> | ||
3 | + <li class="sort-item active"><span>默认</span></li> | ||
4 | + <li class="sort-item"> | ||
5 | + <span class="sort-name">最新</span> | ||
6 | + </li> | ||
7 | + <li class="sort-item"> | ||
8 | + <span class="sort-name">价格</span> | ||
9 | + </li> | ||
10 | + <li class="sort-item"> | ||
11 | + <span class="sort-name">折扣</span> | ||
12 | + </li> | ||
13 | + </ul> | ||
14 | +</template> | ||
15 | +<script> | ||
16 | +module.exports = { | ||
17 | + | ||
18 | +} | ||
19 | +</script> | ||
20 | +<style> | ||
21 | +@import '../../scss/common/color'; | ||
22 | + | ||
23 | +.sort-navs { | ||
24 | + list-style: none; | ||
25 | + margin: 0; | ||
26 | + padding: 25px 0; | ||
27 | + color: $grey; | ||
28 | +} | ||
29 | + | ||
30 | +.sort-item { | ||
31 | + position: relative; | ||
32 | + display: block; | ||
33 | + width: 25%; | ||
34 | + float: left; | ||
35 | + text-align: center; | ||
36 | + | ||
37 | + &:after { | ||
38 | + content: '|'; | ||
39 | + position: absolute; | ||
40 | + right: 0; | ||
41 | + color: $grey; | ||
42 | + font-size: 28px; | ||
43 | + } | ||
44 | + &:last-of-type:after { | ||
45 | + display: none; | ||
46 | + } | ||
47 | + | ||
48 | + .sort-name { | ||
49 | + font-size: 28px; | ||
50 | + } | ||
51 | + | ||
52 | + &.active { | ||
53 | + color: $black; | ||
54 | + } | ||
55 | +} | ||
56 | +</style> |
public/vue/pages/products-list.vue
0 → 100644
-
Please register or login to post a comment