Showing
9 changed files
with
244 additions
and
60 deletions
1 | 1 | ||
2 | 'use strict'; | 2 | 'use strict'; |
3 | -let couponsModel = require('../models/coupons-model'); | 3 | +let couponsModel = require('../models/coupon-service'); |
4 | 4 | ||
5 | const index = (req, res, next)=>{ | 5 | const index = (req, res, next)=>{ |
6 | let uid = req.user.uid; | 6 | let uid = req.user.uid; |
7 | 7 | ||
8 | - req.ctx(couponsModel).couponsData(uid, req.query).then(result => { | 8 | + req.ctx(couponsModel).getCouponData(uid, req.query).then(result => { |
9 | res.render('coupons', result); | 9 | res.render('coupons', result); |
10 | }).catch(next); | 10 | }).catch(next); |
11 | }; | 11 | }; |
apps/home/models/coupon-api.js
0 → 100644
1 | +module.exports = class extends global.yoho.BaseModel { | ||
2 | + constructor(ctx) { | ||
3 | + super(ctx); | ||
4 | + } | ||
5 | + | ||
6 | + getCouponList(uid, type, page, extra) { | ||
7 | + extra = extra || {}; | ||
8 | + | ||
9 | + let reqData = { | ||
10 | + method: 'app.coupons.get', | ||
11 | + uid: uid, | ||
12 | + type: type || 'notuse', | ||
13 | + page: page || 1, | ||
14 | + limit: extra.limit || 10 | ||
15 | + }; | ||
16 | + | ||
17 | + if (extra.filter) { | ||
18 | + reqData.filter = extra.filter; | ||
19 | + } | ||
20 | + | ||
21 | + return this.get({data: reqData}); | ||
22 | + } | ||
23 | + | ||
24 | + getCouponNum(uid) { | ||
25 | + return this.get({data: { | ||
26 | + method: 'app.coupons.getCouponNums', | ||
27 | + uid: uid | ||
28 | + }}); | ||
29 | + } | ||
30 | +}; |
apps/home/models/coupon-service.js
0 → 100644
1 | + | ||
2 | +const _ = require('lodash'); | ||
3 | +const CouponApi = require('./coupon-api'); | ||
4 | + | ||
5 | +const helpers = global.yoho.helpers; | ||
6 | +const setPager = require(`${global.utils}/pager`).setPager; | ||
7 | + | ||
8 | +const COUPON_BASE_URI = '/home/coupons'; | ||
9 | +const COUPON_TYPE = { | ||
10 | + UNUSED: 'notuse', | ||
11 | + USED: 'use', | ||
12 | + INVALID: 'overtime' | ||
13 | +}; | ||
14 | + | ||
15 | +module.exports = class extends global.yoho.BaseModel { | ||
16 | + constructor(ctx) { | ||
17 | + super(ctx); | ||
18 | + } | ||
19 | + | ||
20 | + _setShowNum(num) { | ||
21 | + num = num > 0 ? num : 0; | ||
22 | + num = num > 99 ? '99+' : num; | ||
23 | + | ||
24 | + return num ? `(${num})` : ''; | ||
25 | + } | ||
26 | + | ||
27 | + _setCouponTabs(nums, type) { | ||
28 | + nums = nums || {}; | ||
29 | + | ||
30 | + return [ | ||
31 | + { | ||
32 | + active: type === COUPON_TYPE.UNUSED, | ||
33 | + url: helpers.urlFormat(COUPON_BASE_URI), | ||
34 | + name: `可用${this._setShowNum(nums[COUPON_TYPE.UNUSED])}` | ||
35 | + }, | ||
36 | + { | ||
37 | + active: type === COUPON_TYPE.USED, | ||
38 | + url: helpers.urlFormat(COUPON_BASE_URI, {type: COUPON_TYPE.USED}), | ||
39 | + name: `已使用${this._setShowNum(nums[COUPON_TYPE.USED])}` | ||
40 | + }, | ||
41 | + { | ||
42 | + active: type === COUPON_TYPE.INVALID, | ||
43 | + url: helpers.urlFormat(COUPON_BASE_URI, {type: COUPON_TYPE.INVALID}), | ||
44 | + name: `已失效${this._setShowNum(nums[COUPON_TYPE.INVALID])}` | ||
45 | + } | ||
46 | + ]; | ||
47 | + } | ||
48 | + | ||
49 | + getCouponData(uid, params) { | ||
50 | + params = params || {}; | ||
51 | + | ||
52 | + const page = parseInt(`0${params.page}`, 10) || 1; | ||
53 | + const type = params.type || COUPON_TYPE.UNUSED; | ||
54 | + const couponApiCase = new CouponApi(this.ctx); | ||
55 | + let resData = {}; | ||
56 | + | ||
57 | + return Promise.all([ | ||
58 | + couponApiCase.getCouponList(uid, params.type, page, params), | ||
59 | + couponApiCase.getCouponNum(uid) | ||
60 | + ]).then(result => { | ||
61 | + Object.assign(resData, _.get(result, '[0].data', {})); | ||
62 | + | ||
63 | + if (resData.couponList && resData.couponList.length) { | ||
64 | + _.forEach(resData.couponList, value => { | ||
65 | + if (type === COUPON_TYPE.USED) { | ||
66 | + value.isUsed = true; | ||
67 | + } else if (type === COUPON_TYPE.INVALID) { | ||
68 | + if (value.is_overtime === 'Y') { | ||
69 | + value.isOvertime = true; | ||
70 | + } else { | ||
71 | + value.isUseless = true; | ||
72 | + } | ||
73 | + } else { | ||
74 | + value.toUse = helpers.urlFormat('', {cpc_id: value.coupon_id, coupon_code: value.coupon_code, | ||
75 | + phrase: encodeURIComponent('以下商品可使用 【' + value.coupon_name + '】优惠券')}, 'list'); | ||
76 | + } | ||
77 | + }); | ||
78 | + } else { | ||
79 | + resData.couponList = false; | ||
80 | + } | ||
81 | + | ||
82 | + | ||
83 | + resData.tabs = this._setCouponTabs(_.get(result, '[1].data', {}), type); | ||
84 | + | ||
85 | + if (_.get(resData, 'tabs[0].active') && resData.filters) { | ||
86 | + const filterUrl = helpers.urlFormat(COUPON_BASE_URI, | ||
87 | + Object.assign({}, params, {filter: '__filter__', page: 1})); | ||
88 | + let filter = params.filter || 0; | ||
89 | + | ||
90 | + _.forEach(resData.filters, value => { | ||
91 | + if ((+filter === +value.filter_id)) { | ||
92 | + value.active = true; | ||
93 | + value.url = 'javascript:;'; // eslint-disable-line | ||
94 | + } else { | ||
95 | + value.url = filterUrl.replace('__filter__', value.filter_id); | ||
96 | + } | ||
97 | + }); | ||
98 | + } else { | ||
99 | + resData.filters = false; | ||
100 | + } | ||
101 | + | ||
102 | + let total = _.get(resData, 'total', 0); | ||
103 | + let pageTotal = _.get(resData, 'pageNum') || 1; | ||
104 | + | ||
105 | + resData.pager = Object.assign({ | ||
106 | + count: total, | ||
107 | + curPage: page, | ||
108 | + totalPages: pageTotal | ||
109 | + }, setPager(pageTotal, params)); | ||
110 | + | ||
111 | + return resData; | ||
112 | + }); | ||
113 | + | ||
114 | + } | ||
115 | +}; |
@@ -12,73 +12,54 @@ | @@ -12,73 +12,54 @@ | ||
12 | <button class="code-sure-btn right">兑换</button> | 12 | <button class="code-sure-btn right">兑换</button> |
13 | <input type="text" class="code-input right" placeholder="请输入优惠券码"> | 13 | <input type="text" class="code-input right" placeholder="请输入优惠券码"> |
14 | </div> | 14 | </div> |
15 | + {{#if filters}} | ||
15 | <div class="type-wrap"> | 16 | <div class="type-wrap"> |
16 | - <label class="active">全部优惠券</label> | ||
17 | - <label>店铺券</label> | ||
18 | - <label>活动券</label> | ||
19 | - <label>运费券</label> | 17 | + {{# filters}} |
18 | + <a href="{{url}}" class="type-item{{#if active}} active{{/if}}">{{filter_name}}</a> | ||
19 | + {{/ filters}} | ||
20 | </div> | 20 | </div> |
21 | + {{/if}} | ||
21 | </div> | 22 | </div> |
22 | <div class="coupons-wrap clearfix"> | 23 | <div class="coupons-wrap clearfix"> |
23 | - <div class="coupon-item"> | 24 | + {{# couponList}} |
25 | + <div class="coupon-item{{#if isUsed}} used{{/if}}{{#if isOvertime}} over-time{{/if}}{{#if isUseless}} useless{{/if}}"> | ||
24 | <div class="border"> | 26 | <div class="border"> |
27 | + {{#isY is_overdue_soon}} | ||
25 | <div class="due-tig"></div> | 28 | <div class="due-tig"></div> |
29 | + {{/isY}} | ||
26 | <div class="worth"> | 30 | <div class="worth"> |
27 | - <p>¥<span class="price">100</span><br><span class="conditions">满499可用</span></p> | 31 | + {{#isEqual catalog 300}} |
32 | + <p><span class="freight">{{../coupon_value_str}}</span></p> | ||
33 | + {{^}} | ||
34 | + <p>¥<span class="price">{{../coupon_value_str}}</span><br><span class="conditions">{{../use_rule}}</span></p> | ||
35 | + {{/isEqual}} | ||
28 | </div> | 36 | </div> |
29 | <div class="coupon-info"> | 37 | <div class="coupon-info"> |
30 | - <p class="name"><span class="type type-s">[店铺券]</span> Adidas Origins店铺使用</p> | ||
31 | - <p class="time">2018.1.12-2018.5.20</p> | 38 | + <p class="name"><span class="type type-{{catalog}}">[{{catalog_name}}]</span>{{coupon_name}}</p> |
39 | + <p class="time">{{coupon_validity}}</p> | ||
40 | + {{#if notes}} | ||
32 | <label class="explain"> | 41 | <label class="explain"> |
33 | 使用说明 > | 42 | 使用说明 > |
34 | <p class="explain-wrap"> | 43 | <p class="explain-wrap"> |
35 | - 全场通用,特例商品暂不支持使用优惠券<br>可以与其他类型叠加使用,同店铺只能使用一张,不同店铺可以叠加使用 | 44 | + {{# notes}} |
45 | + {{{.}}}<br> | ||
46 | + {{/ notes}} | ||
36 | </p> | 47 | </p> |
37 | </label> | 48 | </label> |
49 | + {{/if}} | ||
38 | </div> | 50 | </div> |
39 | - <a href="" class="use-now-btn">立即使用</a> | ||
40 | - </div> | ||
41 | - </div> | ||
42 | - <div class="coupon-item used"> | ||
43 | - <div class="border"> | ||
44 | - <div class="worth"> | ||
45 | - <p>¥<span class="price">100</span><br><span class="conditions">满499可用</span></p> | ||
46 | - </div> | ||
47 | - <div class="coupon-info"> | ||
48 | - <p class="name"><span class="type type-a">[店铺券]</span> Adidas Origins店铺使用</p> | ||
49 | - <p class="time">2018.1.12-2018.5.20</p> | ||
50 | - <label class="explain">使用说明 ></label> | ||
51 | - </div> | ||
52 | - <a href="" class="use-now-btn">立即使用</a> | ||
53 | - </div> | ||
54 | - </div> | ||
55 | - <div class="coupon-item over-time"> | ||
56 | - <div class="border"> | ||
57 | - <div class="worth"> | ||
58 | - <p><span class="freight">普通</span></p> | ||
59 | - </div> | ||
60 | - <div class="coupon-info"> | ||
61 | - <p class="name"><span class="type type-d">[运费券]</span> 8月份运费券</p> | ||
62 | - <p class="time">2018.1.12-2018.5.20</p> | ||
63 | - <label class="explain">使用说明 ></label> | ||
64 | - </div> | ||
65 | - <a href="" class="use-now-btn">立即使用</a> | ||
66 | - </div> | ||
67 | - </div> | ||
68 | - <div class="coupon-item useless"> | ||
69 | - <div class="border"> | ||
70 | - <div class="worth"> | ||
71 | - <p><span class="freight">顺丰</span></p> | ||
72 | - </div> | ||
73 | - <div class="coupon-info"> | ||
74 | - <p class="name"><span class="type type-d">[运费券]</span> 8月份运费券</p> | ||
75 | - <p class="time">2018.1.12-2018.5.20</p> | ||
76 | - <label class="explain">使用说明 ></label> | ||
77 | - </div> | ||
78 | - <a href="" class="use-now-btn">立即使用</a> | 51 | + {{# toUse}} |
52 | + <a href="{{.}}" class="use-now-btn" target="_blank">立即使用</a> | ||
53 | + {{/ toUse}} | ||
79 | </div> | 54 | </div> |
80 | </div> | 55 | </div> |
56 | + {{/ couponList}} | ||
57 | + | ||
58 | + {{#unless couponList}} | ||
59 | + <p class="empty-tip">您没有优惠券</p> | ||
60 | + {{/unless}} | ||
81 | </div> | 61 | </div> |
62 | + {{> pager}} | ||
82 | </div> | 63 | </div> |
83 | </div> | 64 | </div> |
84 | </div> | 65 | </div> |
@@ -4,7 +4,7 @@ | @@ -4,7 +4,7 @@ | ||
4 | <label class="type-item type-200" data-type="200">活动券</label> | 4 | <label class="type-item type-200" data-type="200">活动券</label> |
5 | <label class="type-item type-300" data-type="300">运费券</label> | 5 | <label class="type-item type-300" data-type="300">运费券</label> |
6 | </div> | 6 | </div> |
7 | -<div class="head-msg fw300">{{headMsg}}</div> | 7 | +<div class="head-msg fw300">{{{headMsg}}}</div> |
8 | <div class="list-content"> | 8 | <div class="list-content"> |
9 | {{#each usableCoupon}} | 9 | {{#each usableCoupon}} |
10 | <div class="list-{{@key}} type-content clearfix"> | 10 | <div class="list-{{@key}} type-content clearfix"> |
@@ -557,15 +557,15 @@ coupon = { | @@ -557,15 +557,15 @@ coupon = { | ||
557 | that.$couponUsableWrap.html(couponUsableTpl(data)); | 557 | that.$couponUsableWrap.html(couponUsableTpl(data)); |
558 | that.setTabItemNum('usable', data.usableNum); | 558 | that.setTabItemNum('usable', data.usableNum); |
559 | 559 | ||
560 | - usedText = data.usableNum ? `可用${data.usableNum}张` : ''; | 560 | + usedText = data.usableNum ? `${data.usableNum}张可用` : ''; |
561 | 561 | ||
562 | // 更新使用数量 | 562 | // 更新使用数量 |
563 | usedNum = that.$couponWrap.find('.coupon-item.active').length; | 563 | usedNum = that.$couponWrap.find('.coupon-item.active').length; |
564 | 564 | ||
565 | if (hasCode) { | 565 | if (hasCode) { |
566 | + usedText = usedNum ? `已选${usedNum}张` : usedText; | ||
566 | order.couponCode = data.usedCouponCode; | 567 | order.couponCode = data.usedCouponCode; |
567 | compute(0); // 重新计算价格 | 568 | compute(0); // 重新计算价格 |
568 | - usedText = usedNum ? `已选${usedNum}张` : usedText; | ||
569 | } else { | 569 | } else { |
570 | usedText += usedNum ? ` 已推荐${usedNum}张` : ''; | 570 | usedText += usedNum ? ` 已推荐${usedNum}张` : ''; |
571 | } | 571 | } |
@@ -616,7 +616,7 @@ coupon = { | @@ -616,7 +616,7 @@ coupon = { | ||
616 | } | 616 | } |
617 | 617 | ||
618 | if (!this.$codeUseTip) { | 618 | if (!this.$codeUseTip) { |
619 | - this.$codeUseTip = $('.code-use-tip', this.$el); | 619 | + this.$codeUseTip = $('.code-use-tip', this.$couponWrap); |
620 | } | 620 | } |
621 | 621 | ||
622 | this.$codeUseTip.text(tip); | 622 | this.$codeUseTip.text(tip); |
@@ -748,6 +748,8 @@ coupon = { | @@ -748,6 +748,8 @@ coupon = { | ||
748 | } else { | 748 | } else { |
749 | that.$couponCodeUse.removeClass('sure-convert-btn'); | 749 | that.$couponCodeUse.removeClass('sure-convert-btn'); |
750 | } | 750 | } |
751 | + | ||
752 | + that.showCodeUseTip(); | ||
751 | }).on('click', '.sure-convert-btn', function() { | 753 | }).on('click', '.sure-convert-btn', function() { |
752 | that.useCode(that.$couponCode.val()); | 754 | that.useCode(that.$couponCode.val()); |
753 | }).on('click', '.usable-wrap .coupon-item', function() { | 755 | }).on('click', '.usable-wrap .coupon-item', function() { |
1 | var $ = require('yoho-jquery'); | 1 | var $ = require('yoho-jquery'); |
2 | -var yas = require('../common/data-yas'); | 2 | +var yas = require('../common/data-yas'), |
3 | + dialog = require('../common/dialog'); | ||
4 | + | ||
5 | +var $couponCodeUse = $('.code-sure-btn'), | ||
6 | + $codeInput = $('.code-input'); | ||
3 | 7 | ||
4 | require('../common'); | 8 | require('../common'); |
5 | 9 | ||
@@ -10,3 +14,29 @@ $('.use-now-btn').click(function() { | @@ -10,3 +14,29 @@ $('.use-now-btn').click(function() { | ||
10 | yas.yasEvent('YB_COUPON_IMMEDIATE_USE_C', {COUPON_ID: couponid}); | 14 | yas.yasEvent('YB_COUPON_IMMEDIATE_USE_C', {COUPON_ID: couponid}); |
11 | } | 15 | } |
12 | }); | 16 | }); |
17 | + | ||
18 | +$codeInput.keyup(function() { | ||
19 | + if ($.trim($(this).val())) { | ||
20 | + $couponCodeUse.addClass('sure-convert-btn'); | ||
21 | + } else { | ||
22 | + $couponCodeUse.removeClass('sure-convert-btn'); | ||
23 | + } | ||
24 | +}); | ||
25 | + | ||
26 | +$couponCodeUse.click(function() { | ||
27 | + var code = $.trim($codeInput.val()); | ||
28 | + | ||
29 | + if ($(this).hasClass('sure-convert-btn') && code) { | ||
30 | + $.ajax({ | ||
31 | + type: 'GET', | ||
32 | + url: '/cart/ensure/couponcode', | ||
33 | + data: {code: code} | ||
34 | + }).then(function(data) { | ||
35 | + if (data.code === 200) { | ||
36 | + window.location.reload(); | ||
37 | + } else { | ||
38 | + new dialog.Alert(data.message || '兑换失败,请稍后再试').show(); | ||
39 | + } | ||
40 | + }); | ||
41 | + } | ||
42 | +}); |
@@ -1214,7 +1214,7 @@ | @@ -1214,7 +1214,7 @@ | ||
1214 | .name { | 1214 | .name { |
1215 | max-width: 90%; | 1215 | max-width: 90%; |
1216 | height: 36px; | 1216 | height: 36px; |
1217 | - line-height: 1.3; | 1217 | + line-height: 1.4; |
1218 | font-size: 13px; | 1218 | font-size: 13px; |
1219 | color: #444; | 1219 | color: #444; |
1220 | overflow: hidden; | 1220 | overflow: hidden; |
@@ -1222,6 +1222,15 @@ | @@ -1222,6 +1222,15 @@ | ||
1222 | 1222 | ||
1223 | .type { | 1223 | .type { |
1224 | font-weight: bold; | 1224 | font-weight: bold; |
1225 | + margin-right: 4px; | ||
1226 | + } | ||
1227 | + | ||
1228 | + .type-100 { | ||
1229 | + color: #efaf46; | ||
1230 | + } | ||
1231 | + | ||
1232 | + .type-200 { | ||
1233 | + color: #fc5960; | ||
1225 | } | 1234 | } |
1226 | 1235 | ||
1227 | .time { | 1236 | .time { |
@@ -38,6 +38,10 @@ | @@ -38,6 +38,10 @@ | ||
38 | padding: 0; | 38 | padding: 0; |
39 | border: 0; | 39 | border: 0; |
40 | } | 40 | } |
41 | + | ||
42 | + .sure-convert-btn { | ||
43 | + background: #444; | ||
44 | + } | ||
41 | } | 45 | } |
42 | 46 | ||
43 | .tabs { | 47 | .tabs { |
@@ -76,7 +80,7 @@ | @@ -76,7 +80,7 @@ | ||
76 | font-size: 0; | 80 | font-size: 0; |
77 | border-bottom: 1px solid #e0e0e0; | 81 | border-bottom: 1px solid #e0e0e0; |
78 | 82 | ||
79 | - > label { | 83 | + .type-item { |
80 | min-width: 90px; | 84 | min-width: 90px; |
81 | height: 30px; | 85 | height: 30px; |
82 | line-height: 28px; | 86 | line-height: 28px; |
@@ -90,7 +94,7 @@ | @@ -90,7 +94,7 @@ | ||
90 | cursor: pointer; | 94 | cursor: pointer; |
91 | } | 95 | } |
92 | 96 | ||
93 | - > label:first-child { | 97 | + .type-item:first-child { |
94 | margin-left: 0; | 98 | margin-left: 0; |
95 | } | 99 | } |
96 | 100 | ||
@@ -110,6 +114,10 @@ | @@ -110,6 +114,10 @@ | ||
110 | font-size: 0; | 114 | font-size: 0; |
111 | } | 115 | } |
112 | 116 | ||
117 | + .empty-tip { | ||
118 | + font-size: 12px; | ||
119 | + } | ||
120 | + | ||
113 | .coupon-item { | 121 | .coupon-item { |
114 | width: 354px; | 122 | width: 354px; |
115 | height: 100px; | 123 | height: 100px; |
@@ -199,7 +207,7 @@ | @@ -199,7 +207,7 @@ | ||
199 | .name { | 207 | .name { |
200 | max-width: 90%; | 208 | max-width: 90%; |
201 | height: 36px; | 209 | height: 36px; |
202 | - line-height: 1.3; | 210 | + line-height: 1.4; |
203 | font-size: 13px; | 211 | font-size: 13px; |
204 | color: #444; | 212 | color: #444; |
205 | overflow: hidden; | 213 | overflow: hidden; |
@@ -207,6 +215,15 @@ | @@ -207,6 +215,15 @@ | ||
207 | 215 | ||
208 | .type { | 216 | .type { |
209 | font-weight: bold; | 217 | font-weight: bold; |
218 | + margin-right: 4px; | ||
219 | + } | ||
220 | + | ||
221 | + .type-100 { | ||
222 | + color: #efaf46; | ||
223 | + } | ||
224 | + | ||
225 | + .type-200 { | ||
226 | + color: #fc5960; | ||
210 | } | 227 | } |
211 | 228 | ||
212 | .time { | 229 | .time { |
-
Please register or login to post a comment