/** * 购物车选择尺寸、颜色和数量面板 * @author: feng.chen<feng.chen@yoho.cn> * @date: 2017/3/2 * 示例: * let chosePanel = require('chose-panel-new'); * chosePanel.show({ * data: {}, // 商品数据 * buttonText: '加入购物车', // 自定义底部按钮文字 * disableNum: true // 禁用编辑数量 * }).then((sku) => { * //点击确认按钮回调,返回sku对象,各自业务在此处实现,该组件不做选择后的处理 * //... * }, () => { * //关闭选择框回调 * }); * choselPanel.close(); //关闭选择框 */ let $ = require('yoho-jquery'), tip = require('plugin/tip'), innerScroll = require('plugin/inner-scroll'); let panelT = require('common/chose-panel-new.hbs'); let $yohoPage = $('.yoho-page'), $chosePanel = $('.chose-panel'), $choseArea, $goodNum, $btnMinus, $thumbImg, $choseBtnSure, $noChoose, $chooseInfo; class ChosePanel { constructor() { if (!window.cookie) { require('common'); } this.C_ID = window._ChannelVary[window.cookie('_Channel')]; this._regEvents(); } show(opt) { if (!opt) { $('.chose-panel').show(); return new Promise((resolve, reject) => { this._resolve = resolve; this._reject = reject; }); } Object.assign(this, opt); if (!this.data) { throw new Error('未赋值'); } if (this.data) { this._setModes(); this.maxBuyNum = this.data.cartInfo.limit || 0; // 0表示不限制购买 this.skus = this.data.cartInfo.skus || []; this.props = this.data.cartInfo.props || []; this.buyNum = this._defaultBuyNum(); this.minBuyNum = (this.modes.discount && this.data.discountBuy.num) || 1; this.setting = { disableNum: this.disableNum, noChoseText: `请选择${this.props.map(prop => prop.name).join('、')}`, buttonText: this.buttonText || this._getButtonText(), buyNum: this.buyNum }; } this._render(); return new Promise((resolve, reject) => { this._resolve = resolve; this._reject = reject; }); } close() { innerScroll.enableScroll($choseArea); $('.chose-panel').hide(); } /** * 设置商品模式 */ _setModes() { this.modes = { // 商品特性 discount: this.data.discountBuy ? true : false, // 量贩 tickets: this.data.tickets ? true : false, // 门票 limitCode: this.data.cartInfo.limitProductCode ? true : false, // 限购 limit: this.data.cartInfo.limit ? true : false, // 限制购买数量 soonSoldOut: $('.soon-sold-out-tag').length ? true : false, // 即将售罄 seckill: $('.seckill-time').length ? true : false, // 秒杀 disableNum: this.disableNum, // 禁用编辑 showBuyNow: this.data.showBuyNow // 是否显示双按钮 }; } _render() { let html; html = panelT(Object.assign(this.data, this.setting)); if ($chosePanel.length) { $chosePanel.replaceWith(html); } else { $yohoPage.append(html); } this._setVariable(); this._initBlockStatus(); innerScroll.disableScroll($choseArea); } _getButtonText() { if (this.modes.showBuyNow) { return { double: true, text: '加入购物车' }; } if (this.modes.tickets || this.modes.limitCode || this.modes.seckill) { return { double: false, text: '立即购买' }; } return { double: false, text: '加入购物车' }; } _defaultBuyNum() { return (this.modes.discount && this.data.discountBuy.num) || (this.data.cartInfo && this.data.cartInfo.num) || 1; } /** * 初始化属性按钮状态不满足库存的灰色 */ _initBlockStatus() { // 获取sku列表中库存小于最小购买数量的属性,如果在其他sku中它们没有满足购买数量条件的可以灰色 let noStorageSkus = this.skus.filter(sku => sku.storage < this.minBuyNum); $chosePanel.find('.thumb').attr('src', this.data.cartInfo.defaultThumb); $('.block').removeClass('zero-stock'); noStorageSkus.forEach(sku => { for (let propType in sku.prop) { if (propType) { let prop = sku.prop[propType]; let zeroStock = !this.skus.some(_ => _.prop[propType].valId === prop.valId && _.storage >= this.minBuyNum); let $block = $(`.block[data-prop-id="${propType}"][data-value-id="${prop.valId}"]`); if (zeroStock) { $block.addClass('zero-stock'); } else { $block.removeClass('zero-stock'); } } } }); } _setVariable() { $chosePanel = $('.chose-panel'); $choseArea = $('.chose-panel .main .chose-items'); $goodNum = $('#good-num'); $btnMinus = $('.btn-minus'); $thumbImg = $('.thumb-img'); $choseBtnSure = $('#chose-btn-sure'); $noChoose = $('.not-choose'); $chooseInfo = $('.choosed-info'); } _regEvents() { $yohoPage.on('touchstart', '.chose-panel', (e) => { return this._closeClick(e); }); $yohoPage.on('touchstart', '.block', (e) => { this._blockClick(e); }); $yohoPage.on('touchstart', '.btn-plus,.btn-minus', (e) => { this._numClick(e); }); $yohoPage.on('touchstart', '.thumb-img .thumb', (e) => { this._thumbClick(e); }); $yohoPage.on('touchstart', '#chose-btn-sure', (e) => { return this._choseBtnSureClick(e, false); }); $yohoPage.on('touchstart', '#chose-btn-buynow', (e) => { let sku = this._checkSku(this.buyNum); if (window._yas && window._yas.sendCustomInfo) { window._yas.sendCustomInfo({ op: 'YB_GDS_BUYNOW_BTN', param: JSON.stringify({ C_ID: this.C_ID, PRD_ID: this.data.cartInfo.productId, PRD_NUM: this.buyNum, PRD_SKN: this.data.cartInfo.productSkn, PRD_SKU: sku && sku.skuId }) }, true); } return this._choseBtnSureClick(e, true); }); } /** * 点击关闭按钮 */ _closeClick(e) { let $cur = $(e.target); if ($cur.closest('.main').length > 0 && !$cur.hasClass('close')) { return; } this.close(); this._reject && this._reject(); return false; } /** * 点击属性 */ _blockClick(e) { let $block = $(e.currentTarget); if ($block.hasClass('chosed')) { $block.removeClass('chosed'); } else { $block.addClass('chosed').siblings().removeClass('chosed'); } this._selectBlock($block); } /** * 点击数量加减 */ _numClick(e) { let buyNum; if (this.modes.disableNum) { return; } buyNum = $(e.currentTarget).hasClass('btn-minus') ? this.buyNum - 1 : this.buyNum + 1; if (this._checkSku(buyNum)) { this.buyNum = buyNum; $goodNum.val(this.buyNum); if (this.modes.discount) { if (buyNum <= this.minBuyNum) { $('.btn-minus').addClass('discount-gray'); } else { $('.btn-minus').removeClass('discount-gray'); } } } } /** * 点击缩略图 */ _thumbClick() { if ($thumbImg.hasClass('hover')) { $thumbImg.removeClass('hover'); } else { $thumbImg.addClass('hover'); } } /** * 点击确定或者立即购买按钮 */ _choseBtnSureClick(e, buyNow) { let selectSku = this._checkSku(this.buyNum); if (selectSku) { this.close(); this._resolve && this._resolve({ sku: selectSku, skn: this.data.cartInfo.productSkn, productId: this.data.cartInfo.productId, buyNum: this.buyNum, modes: this.modes, buyNow: buyNow }); return false; } } /** * 验证选择sku的购买数量是否通过 */ _checkSku(buyNum) { if ($('.block.chosed.zero-stock').length) { return false; } let validSelects = this.props .filter(prop => !$(`.block[data-prop-id="${prop.type}"]`).hasClass('chosed')) .map(prop => { return prop.name; }); if (validSelects.length) { tip.show(`请选择${validSelects.join('和')}~`); return false; } let selectSku = this._getSelectSku(); if (!selectSku) { tip.show('无法选择该属性的商品'); return false; } if (buyNum < this.minBuyNum) { if (this.modes.discount) { tip.show(`量贩商品,${this.minBuyNum}件起购`); return false; } else { tip.show('您选择的数量不能为零~'); return false; } } if (this.modes.tickets && buyNum > selectSku.limitNum) { if (selectSku.limitNum) { tip.show(`每人只可购买${selectSku.limitNum}张此门票`); return false; } } if (this.modes.limit && buyNum > this.maxBuyNum) { tip.show('您选择数量大于限购数量~'); return false; } if (buyNum > selectSku.storage) { tip.show('您选择的数量超过了最大库存量~'); return false; } return selectSku; } /** * 选择属性 */ _selectBlock($selectBlock) { let that = this; let propId = $selectBlock.data('prop-id'), valueId = $selectBlock.data('value-id'); let chosed = $($selectBlock).hasClass('chosed'); if ($('.block.chosed').length === 0) { this._initBlockStatus(); } else { // 根据选择的属性值筛选出符合条件的sku列表,然后遍历其他属性如果在sku列表中不存在该属性值,则灰色 let filterSkus = this.skus.filter(sku => (!chosed || sku.prop[propId].valId === valueId) && sku.storage >= this.minBuyNum); let filterProps = this.props.filter(prop => prop.type !== propId); filterProps.forEach(prop => { $(`.block[data-prop-id="${prop.type}"]`).each((i, ele) => { let $block = $(ele); let valId = $block.data('value-id'); let existsSku = filterSkus.some(sku => sku.prop[prop.type].valId === valId); let fsku = that.skus.filter(sku => sku.prop[propId].valId === valueId && sku.prop[prop.type].valId === valId); let limitTip = ''; if (!existsSku) { $block.addClass('zero-stock'); if (fsku.length && fsku[0].limitBuyTip) { limitTip = fsku[0].limitBuyTip; } } else { $block.removeClass('zero-stock'); } $block.data('limittip', limitTip); }); }); } if (window._yas && window._yas.sendCustomInfo && chosed) { if (propId === 'color') { window._yas.sendCustomInfo({ op: 'YB_GDS_COLOR_C', param: JSON.stringify({ C_ID: this.C_ID, PRD_ID: this.data.cartInfo.productId, COLOR: $selectBlock.text() }) }, true); } else if (propId === 'size') { window._yas.sendCustomInfo({ op: 'YB_GDS_SIZE_C', param: JSON.stringify({ C_ID: this.C_ID, PRD_ID: this.data.cartInfo.productId, SIZE: $selectBlock.text() }) }, true); } } this._refreshBlockStatus(); } /** * 选择属性后刷新其他属性的状态 */ _refreshBlockStatus() { let selectSku = this._getSelectSku(); let $zeroChose = $('.block.chosed.zero-stock'); // 设置底部按钮文字 if ($zeroChose.length) { let tipText = '已售罄'; if ($zeroChose.data('limittip')) { tipText = $zeroChose.data('limittip'); } $choseBtnSure.css('background-color', '#c0c0c0').text(tipText); } else { $choseBtnSure.css('background-color', '#eb0313').text(this.setting.buttonText.text); } // 设置默认购买数量 this.buyNum = this._defaultBuyNum(); $goodNum.val(this.buyNum); if (this.modes.discount) { $btnMinus.addClass('discount-gray'); } // 根据颜色属性设置缩略图 let $colorBlock = $('.block.chosed[data-prop-id="color"]'); if ($colorBlock.length) { let colorSkus = this.skus.filter(sku => sku.prop.color && sku.prop.color.valId === $colorBlock.data('value-id')); if (colorSkus.length) { let thumb = colorSkus[0].thumb; if (!thumb) { thumb = this.data.cartInfo.defaultThumb; } $chosePanel.find('.thumb').attr('src', thumb); } } // 设置选择属性提示 let valueList = Array.from($('.block.chosed').map((index, ele) => { return $(ele).text(); })); // if (this.modes.tickets) { // let $chosed = $('.block.chosed'); // valueList = Array.from($chosed.not('.hide').map((index, ele) => { // return $(ele).text(); // })); // } if (valueList.length) { $noChoose.addClass('hide'); $chooseInfo.removeClass('hide'); $chooseInfo.text(`已选:${valueList.join('、')}`); } else { $noChoose.removeClass('hide'); $chooseInfo.addClass('hide'); } if (selectSku) { // 设置left-num文字 // let cartInfo = this.data.cartInfo, // numText; let numText; if (selectSku.limitNum) { if (selectSku.limitNum) { numText = `限购${selectSku.limitNum}件`; } else { numText = ''; } } else if (this.modes.soonSoldOut) { numText = '即将售罄'; } else if (selectSku.storage < 4 && selectSku.storage > 0) { numText = `剩余${selectSku.storage}件`; } else { numText = ''; } $chosePanel.find('.left-num').text(numText); $chosePanel.find('.size-info').text(selectSku.sizeInfo).removeClass('hide'); $chosePanel.find('.size-rec').text(selectSku.sizeRec || '').removeClass('hide'); } else { $chosePanel.find('.left-num').text(''); $chosePanel.find('.size-info').text('').addClass('hide'); $chosePanel.find('.size-rec').text('').addClass('hide'); } } /** * 根据已选择的属性值获得符合条件的sku */ _getSelectSku() { let selectValues, selectSku; if ($('.block.chosed').length !== this.props.length) { return; } selectValues = Array.from($('.block.chosed').map((index, ele) => { let $block = $(ele); return { propId: $block.data('prop-id'), valueId: $block.data('value-id') }; })); selectSku = this.skus.filter(sku => { return selectValues .map(value => { return sku.prop[value.propId].valId === value.valueId; }) .filter(match => match).length === this.props.length; }); if (selectSku.length >= 1) { return selectSku[0]; } return; } } module.exports = new ChosePanel();