Authored by yyq

usercenter coupon

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 };
  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 +};
  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 {