Authored by jinhu.tung

modify product size and color

@@ -250,6 +250,21 @@ const index = (req, res, next) => { @@ -250,6 +250,21 @@ const index = (req, res, next) => {
250 }).catch(next); 250 }).catch(next);
251 }; 251 };
252 252
  253 +const getProductInfo = (req, res, next) => {
  254 + const productId = req.query.productId;
  255 + const skn = req.query.skn;
  256 + let uid;
  257 +
  258 + if (req.user && req.user.uid) {
  259 + uid = req.user.uid;
  260 + }
  261 +
  262 + Item.getProductInfo(productId, skn, uid).then(result => {
  263 + res.json(result);
  264 + }).catch(next);
  265 +};
  266 +
253 module.exports = { 267 module.exports = {
254 - index // 组件demo页 268 + index, // 组件demo页
  269 + getProductInfo
255 }; 270 };
@@ -92,6 +92,21 @@ let getProductItemData = (params, url, uid) => { @@ -92,6 +92,21 @@ let getProductItemData = (params, url, uid) => {
92 }); 92 });
93 }; 93 };
94 94
  95 +/**
  96 + * 获取商品尺寸,颜色,和缩略图
  97 + * @function getProductInfo
  98 + * @param { Number } productId 商品ID
  99 + * @param { String } uid 用户ID
  100 + * @param { Number } skn 商品skn
  101 + * @return { Object } 接口返回单个商品的基本信息
  102 + */
  103 +const getProductInfo = (productId, uid, skn) => {
  104 + return itemAPI.getProductBaseAsync(productId, uid, skn).then(result => {
  105 + return itemFUN.setProductData(result);
  106 + });
  107 +};
  108 +
95 module.exports = { 109 module.exports = {
96 - getProductItemData 110 + getProductItemData,
  111 + getProductInfo
97 }; 112 };
@@ -20,6 +20,7 @@ router.get('/list/new', list.newPage); // 新品列表页 @@ -20,6 +20,7 @@ router.get('/list/new', list.newPage); // 新品列表页
20 20
21 router.get(/\/pro_([\d]+)_([\d]+)\/(.*)/, item.index); // 商品详情routers 21 router.get(/\/pro_([\d]+)_([\d]+)\/(.*)/, item.index); // 商品详情routers
22 router.post('/item/togglecollect', fav.product); // 商品详情页 22 router.post('/item/togglecollect', fav.product); // 商品详情页
  23 +router.get('/item/getProductInfo', item.getProductInfo); // 商品详情信息
23 24
24 router.get('/shop/query/all', shop.indexQuery); 25 router.get('/shop/query/all', shop.indexQuery);
25 router.get('/shop/:domain/list', shop.list); 26 router.get('/shop/:domain/list', shop.list);
@@ -216,4 +216,29 @@ exports.checkStorage = (req, res) => { @@ -216,4 +216,29 @@ exports.checkStorage = (req, res) => {
216 }); 216 });
217 }; 217 };
218 218
  219 +// 修改购物车商品颜色和尺寸
  220 +exports.modifyProduct = (req, res) => {
  221 + const uid = req.user && req.user.uid;
  222 + const shoppingKey = req.cookies._SPK;
  223 +
  224 + // swapData => [{"buy_number":"1","selected":"Y","new_product_sku":"735172","old_product_sku":"735171"}]
  225 + const swapData = req.body.swapData;
  226 +
  227 + // console.log("swap data....", {swapData, shoppingKey, uid})
  228 +
  229 + cartModel.modifyProduct({swapData, shoppingKey, uid}).then((result) => {
  230 + // console.log('swap result...:', JSON.stringify(result, '', 4))
  231 + if (result.code === 200) {
  232 + cartModel.getCartData(shoppingKey, uid).then(cartData => {
  233 + res.json(_.merge(
  234 + cartModel.filterCartData(cartData, uid),
  235 + {code: cartData.code, message: result.message})
  236 + );
  237 + });
  238 + } else {
  239 + res.json(result);
  240 + }
  241 + });
  242 +};
  243 +
219 244
@@ -456,6 +456,30 @@ const modifyProductNum = (options) => { @@ -456,6 +456,30 @@ const modifyProductNum = (options) => {
456 }); 456 });
457 }; 457 };
458 458
  459 +const modifyProduct = (options) => {
  460 + let params = {
  461 + method: 'app.Shopping.swap'
  462 + };
  463 +
  464 + _.merge(params, {
  465 + swap_data: options.swapData
  466 + });
  467 +
  468 + if (options.uid) {
  469 + _.merge(params, {
  470 + uid: options.uid
  471 + });
  472 + }
  473 +
  474 + if (options.shoppingKey) {
  475 + _.merge(params, {
  476 + shopping_key: options.shoppingKey
  477 + });
  478 + }
  479 +
  480 + return api.get('', params);
  481 +};
  482 +
459 module.exports = { 483 module.exports = {
460 addToCart, 484 addToCart,
461 getCartData, 485 getCartData,
@@ -463,5 +487,6 @@ module.exports = { @@ -463,5 +487,6 @@ module.exports = {
463 toggleSelectGoods, 487 toggleSelectGoods,
464 removeGoods, 488 removeGoods,
465 filterCartData, 489 filterCartData,
466 - modifyProductNum 490 + modifyProductNum,
  491 + modifyProduct
467 }; 492 };
@@ -22,6 +22,7 @@ router.get('/cart/product/:productId/edit', cartCtrl.editProduct); @@ -22,6 +22,7 @@ router.get('/cart/product/:productId/edit', cartCtrl.editProduct);
22 router.post('/cart/add', cartCtrl.addToCart); 22 router.post('/cart/add', cartCtrl.addToCart);
23 router.post('/cart/toggleSelectGoods', cartCtrl.toggleSelectGoods); 23 router.post('/cart/toggleSelectGoods', cartCtrl.toggleSelectGoods);
24 router.get('/cart/checkStorage', cartCtrl.checkStorage); 24 router.get('/cart/checkStorage', cartCtrl.checkStorage);
  25 +router.put('/cart/updateProduct', cartCtrl.modifyProduct);
25 26
26 // 结算 27 // 结算
27 router.get('/order', auth, order.index); 28 router.get('/order', auth, order.index);
@@ -16,41 +16,58 @@ @@ -16,41 +16,58 @@
16 <div class="content"> 16 <div class="content">
17 <div class="left"> 17 <div class="left">
18 <div class="default-color mb20"> 18 <div class="default-color mb20">
19 - <span class="color-label mr10">Color: </span><span>\{{defaultColor}}</span> 19 + <span class="color-label mr10">Color: </span><span class="selected-color">\{{defaultColor}}</span>
20 </div> 20 </div>
21 21
22 <div class="colors-list mb20"> 22 <div class="colors-list mb20">
23 \{{#each colors}} 23 \{{#each colors}}
24 \{{#isEqual ../defaultColor color}} 24 \{{#isEqual ../defaultColor color}}
25 - <span class="color-item" style="background: \{{rgb}}"> 25 + <span class="color-item current-color \{{#unless selectable}}disabled\{{/unless}}"
  26 + style="background: \{{rgb}}"
  27 + data-imageurl="\{{image pic 100 134}}"
  28 + data-target="\{{proId}}-color-\{{@index}}"
  29 + data-title="\{{color}}">
26 <span class="inner"></span> 30 <span class="inner"></span>
27 </span> 31 </span>
28 \{{^}} 32 \{{^}}
29 - <span class="color-item" style="background: \{{rgb}}"></span> 33 + <span class="color-item \{{#unless selectable}}disabled\{{/unless}}"
  34 + style="background: \{{rgb}}"
  35 + data-imageurl="\{{image pic 100 134}}"
  36 + data-target="\{{proId}}-color-\{{@index}}"
  37 + data-title="\{{color}}">
  38 + <span class="inner"></span>
  39 + </span>
30 \{{/isEqual}} 40 \{{/isEqual}}
31 \{{/each}} 41 \{{/each}}
32 </div> 42 </div>
33 43
  44 + \{{#each colors}}
  45 + <div class="sizes-list \{{#isEqual ../defaultColor color}}current-sizes\{{/isEqual}}" id="\{{proId}}-color-\{{@index}}" style="display: \{{#isEqual ../defaultColor color}}block\{{^}}none\{{/isEqual}};">
34 <div class="default-size mb20"> 46 <div class="default-size mb20">
35 - <span class="size-label mr10">Size: </span><span>\{{defaultSize}}</span> 47 + <span class="size-label mr10">Size: </span><span>\{{../defaultSize}}</span>
36 </div> 48 </div>
37 49
38 <div class="sizes-list mb10"> 50 <div class="sizes-list mb10">
39 \{{#each sizes}} 51 \{{#each sizes}}
40 - \{{#isEqual ../defaultSize this}}  
41 - <span class="size-item mr10 mb10 current">\{{this}}</span> 52 + \{{#isEqual ../../defaultSize name}}
  53 + <span class="size-item mr10 mb10 current \{{#isEqual num 0}}disabled\{{/isEqual}}"
  54 + data-sku="\{{sku}}">\{{name}}</span>
42 \{{^}} 55 \{{^}}
43 - <span class="size-item mr10 mb10">\{{this}}</span> 56 + <span class="size-item mr10 mb10 \{{#isEqual num 0}}disabled\{{/isEqual}}"
  57 + data-sku="\{{sku}}">\{{name}}</span>
44 \{{/isEqual}} 58 \{{/isEqual}}
45 \{{/each}} 59 \{{/each}}
46 </div> 60 </div>
  61 + </div>
  62 + \{{/each}}
  63 +
47 <div class="actions"> 64 <div class="actions">
48 <span class="btn mr20" id="confirm">确定</span> 65 <span class="btn mr20" id="confirm">确定</span>
49 <span class="btn disable" id="cancel">取消</span> 66 <span class="btn disable" id="cancel">取消</span>
50 </div> 67 </div>
51 </div> 68 </div>
52 <div class="right"> 69 <div class="right">
53 - <img src="\{{image defaultImg 100 134}}" class="img-preview"/> 70 + <img src="\{{image defaultImg 100 134}}" class="img-preview" title="\{{defaultColor}}"/>
54 </div> 71 </div>
55 </div> 72 </div>
56 </div> 73 </div>
@@ -3,6 +3,7 @@ var Cart = require('./cart/cart'); @@ -3,6 +3,7 @@ var Cart = require('./cart/cart');
3 var Stepper = require('./cart/stepper'); 3 var Stepper = require('./cart/stepper');
4 4
5 $(function() { 5 $(function() {
  6 + var $this;
6 7
7 // 关闭info-bar 8 // 关闭info-bar
8 $('.info-bar .close').on('click', function() { 9 $('.info-bar .close').on('click', function() {
@@ -51,8 +52,18 @@ $(function() { @@ -51,8 +52,18 @@ $(function() {
51 }); 52 });
52 Cart.sendToFavorite(selectedProducts); 53 Cart.sendToFavorite(selectedProducts);
53 }).delegate('.editable', 'click', function() { 54 }).delegate('.editable', 'click', function() {
  55 + $this = $(this);
  56 +
54 // 编辑商品颜色和属性 57 // 编辑商品颜色和属性
55 - Cart.editColorOrSize($(this).attr('data-productId')); 58 + Cart.editColorOrSize(
  59 + $this.attr('data-productId'),
  60 + $this.attr('data-productSkn'),
  61 + $this.find('.default-color').text(),
  62 + $this.find('.default-size').text());
  63 +
  64 + $('body').on('click', function() {
  65 + $('.edit-color-size').remove();
  66 + });
56 }).delegate('#checkout_btn', 'click', function(e) { 67 }).delegate('#checkout_btn', 'click', function(e) {
57 e.preventDefault(); 68 e.preventDefault();
58 Cart.checkStorage(function() { 69 Cart.checkStorage(function() {
@@ -245,25 +245,57 @@ var Cart = { @@ -245,25 +245,57 @@ var Cart = {
245 }, 245 },
246 246
247 // 编辑商品的颜色和尺寸 247 // 编辑商品的颜色和尺寸
248 - editColorOrSize: function(productId) { 248 + editColorOrSize: function(productId, skn, defaultColor, defaultSize) {
249 var template; 249 var template;
  250 + var index = 0;
  251 + var colors;
  252 + var colorsLen;
  253 + var color;
250 254
251 - Util.ajax({  
252 - url: '/shopping/cart/product/' + productId + '/edit',  
253 - success: function(res) {  
254 - if (res.code === '0') {  
255 - // helpers start  
256 - hbs.registerHelper('multiple', function(num1, num2) {  
257 - num1 = typeof num1 === 'number' ? num1 : parseFloat(num1, 10);  
258 - num2 = typeof num2 === 'number' ? num2 : parseFloat(num2, 10); 255 + // 前端处理后的集合
  256 + var filterSet = [];
  257 + var defaultImg;
  258 + var editTarget = $('#edit_' + productId);
259 259
260 - if (num1 && num2) {  
261 - return num1 * num2;  
262 - } else {  
263 - console.error('multiplication needs two number parameters');  
264 - } 260 + // 选择
  261 + var selectColor;
  262 +
  263 + // sku
  264 + var newProductSku;
  265 + var oldProductSku;
  266 +
  267 + $.ajax({
  268 + type: 'GET',
  269 + url: '/product/item/getProductInfo',
  270 + data: {
  271 + productId: productId,
  272 + skn: skn
  273 + },
  274 + success: function(res) {
  275 + // 没有res.code
  276 + if (res.colors) {
  277 + // 获取成功
  278 + colors = res.colors;
  279 + colorsLen = colors.length;
  280 + for (index; index < colorsLen; index++) {
  281 + color = colors[index];
  282 +
  283 + // 迭代每一种颜色
  284 + filterSet.push({
  285 + proId: res.id,
  286 + color: color.color,
  287 + sizes: color.sizes,
  288 + pic: color.thumbs[0],
  289 + selectable: color.total > 0,
  290 + colorName: color.name
265 }); 291 });
  292 + if (color.color === defaultColor) {
  293 + defaultImg = color.thumbs[0];
  294 + }
  295 + }
  296 + }
266 297
  298 + // helpers start
267 hbs.registerHelper('isEqual', function(v1, v2, options) { 299 hbs.registerHelper('isEqual', function(v1, v2, options) {
268 if (v1 === v2) { 300 if (v1 === v2) {
269 return options.fn(this); 301 return options.fn(this);
@@ -271,16 +303,6 @@ var Cart = { @@ -271,16 +303,6 @@ var Cart = {
271 return options.inverse(this); 303 return options.inverse(this);
272 }); 304 });
273 305
274 - hbs.registerHelper('showStorage', function(leftNumber) {  
275 - leftNumber = typeof num1 === 'number' ? leftNumber : parseFloat(leftNumber, 10);  
276 -  
277 - if (leftNumber <= 3 && leftNumber >= 0) {  
278 - return '仅剩' + leftNumber + '件';  
279 - } else if (leftNumber < 0) {  
280 - return '库存不足';  
281 - }  
282 - });  
283 -  
284 hbs.registerHelper('image', function(url, width, height, mode) { 306 hbs.registerHelper('image', function(url, width, height, mode) {
285 mode = parseInt(mode, 10) ? mode : 2; 307 mode = parseInt(mode, 10) ? mode : 2;
286 url = url || ''; 308 url = url || '';
@@ -291,16 +313,64 @@ var Cart = { @@ -291,16 +313,64 @@ var Cart = {
291 313
292 template = hbs.compile($('#edit-color-size-tpl').html()); 314 template = hbs.compile($('#edit-color-size-tpl').html());
293 315
294 - $('#edit_' + productId).append( 316 +
  317 + editTarget.append(
295 template({ 318 template({
296 - colors: res.colors,  
297 - sizes: res.sizes,  
298 - defaultColor: res.defaultColor,  
299 - defaultSize: res.defaultSize,  
300 - defaultImg: res.defaultImg 319 + colors: filterSet,
  320 + defaultColor: defaultColor,
  321 + defaultSize: defaultSize,
  322 + defaultImg: defaultImg
301 }) 323 })
302 ); 324 );
  325 +
  326 + oldProductSku = editTarget.find('.current-sizes .current').attr('data-sku');
  327 +
  328 + editTarget.delegate('#confirm', 'click', function(e) {
  329 + e.preventDefault();
  330 + Util.ajax({
  331 + url: '/shopping/cart/updateProduct',
  332 + type: 'PUT',
  333 + data: {
  334 + swapData: JSON.stringify([{
  335 + buy_number: '1',
  336 + selected: 'Y',
  337 + new_product_sku: newProductSku,
  338 + old_product_sku: oldProductSku
  339 + }])
  340 + },
  341 + success: function(newCartData) {
  342 + editTarget.find('.edit-color-size').remove();
  343 + Util.refreshCart(newCartData);
303 } 344 }
  345 + });
  346 + return false;
  347 + }).delegate('#cancel', 'click', function(e) {
  348 + e.preventDefault();
  349 + editTarget.find('.edit-color-size').remove();
  350 + return false;
  351 + }).delegate('.edit-color-size', 'click', function(e) {
  352 + e.preventDefault();
  353 + return false;
  354 + }).delegate('.color-item', 'click', function(e) {
  355 + e.preventDefault();
  356 + selectColor = $(this);
  357 + if (!selectColor.hasClass('current-color')) {
  358 + selectColor.addClass('current-color').siblings().removeClass('current-color');
  359 + selectColor.parent().siblings('.current-sizes').hide().removeClass('current-sizes');
  360 + editTarget.find('#' + selectColor.attr('data-target')).show().addClass('current-sizes')
  361 + .end()
  362 + .find('.right img').attr({
  363 + src: selectColor.attr('data-imageurl'),
  364 + title: selectColor.attr('data-title')
  365 + })
  366 + .end()
  367 + .find('.selected-color').text(selectColor.attr('data-title'));
  368 + }
  369 + return false;
  370 + }).delegate('.current-sizes .size-item', 'click', function() {
  371 + $(this).addClass('current').siblings('.current').removeClass('current');
  372 + newProductSku = $(this).attr('data-sku');
  373 + });
304 }, 374 },
305 fail: function() { 375 fail: function() {
306 new _alert('此商品无法编辑颜色和尺寸').show(); 376 new _alert('此商品无法编辑颜色和尺寸').show();
@@ -56,6 +56,11 @@ var Util = { @@ -56,6 +56,11 @@ var Util = {
56 return options.inverse(this); 56 return options.inverse(this);
57 }); 57 });
58 58
  59 + hbs.registerHelper('round', function(num, fixedNum) {
  60 + num = typeof num === 'number' ? num : parseFloat(num, 10);
  61 + return num.toFixed(fixedNum);
  62 + });
  63 +
59 hbs.registerHelper('showStorage', function(leftNumber) { 64 hbs.registerHelper('showStorage', function(leftNumber) {
60 leftNumber = typeof num1 === 'number' ? leftNumber : parseFloat(leftNumber, 10); 65 leftNumber = typeof num1 === 'number' ? leftNumber : parseFloat(leftNumber, 10);
61 66
@@ -41,12 +41,14 @@ @@ -41,12 +41,14 @@
41 color: #fff; 41 color: #fff;
42 } 42 }
43 43
  44 + .current-color {
44 .inner { 45 .inner {
45 border: 2px solid #b0b0b0; 46 border: 2px solid #b0b0b0;
46 width: 18px; 47 width: 18px;
47 height: 18px; 48 height: 18px;
48 display: inline-block; 49 display: inline-block;
49 } 50 }
  51 + }
50 52
51 .right { 53 .right {
52 float: left; 54 float: left;