/** * 商品详情models * @author: xuqi<qi.xu@yoho.cn> * @date: 2016/5/6 */ 'use strict'; const utils = '../../../utils'; const _ = require('lodash'); const comment = require('./consult-comment'); const bundle = require('./bundle'); const api = global.yoho.API; const singleAPI = global.yoho.SingleAPI; const helpers = global.yoho.helpers; const productProcess = require(`${utils}/product-process`); // const SINGLE_TICKETS_SKN = 51335912; // 展览票 module.exports = class extends global.yoho.BaseModel { constructor(ctx) { super(ctx); } /** * 获取用户数据信息 * @param {[string]} uid * @return {[array]} */ _getUserProfile(uid) { if (!uid) { return Promise.resolve({ code: 200, data: {} }); } return this.get({ data: { method: 'app.passport.profile', uid: uid }, param: {cache: true} }).catch(function() { return { code: 200, data: {} }; }); } /** * 处理品牌关联店铺信息 * @param {array} * @return {array} */ _processShopsInfo(data) { let enterStore = []; _.forEach(data, function(value) { let shopInfo = { img: value.brand_ico, storeName: value.brand_name }; if (value.shop_id) { shopInfo.url = helpers.urlFormat('/product/shop', { shop_id: value.shop_id }); } else { shopInfo.url = helpers.urlFormat('', null, value.brand_domain); } enterStore.push(shopInfo); }); return enterStore; } /** * 处理限购商品的有关按钮状态(或取现购买以及底部商品购买按钮) * @param {array} 需要处理的数据 * @param {int} 限购商品的关联状态 * @param {Boolean} 限购商品是否已开售 * @return {array} */ _procShowStatus(data, showStatus, isBeginSale) { switch (showStatus) { case 1: // 开售前/后,立即分享获得限购码(用户未领取限购码) // 显示获取限购码按钮 data.canGetLimitCode = true; if (isBeginSale) { // 开售后 data.cartInfo.noLimitCode = true; } else { data.cartInfo.limitNotForSale = true; } break; case 2: // 开售后,限购码已抢光(用户未领取限购码) data.codeEmpty = true; data.cartInfo.noLimitCode = true; break; case 3: // 开售后,商品已经售罄 data.noLimitGoodsBtn = true; data.cartInfo.soldOut = true; break; case 4: // 开售后,立即购买(用户已领取限购码) data.gotCode = true; data.cartInfo.canNotBuy = true; break; case 5: // 开售前,限购码已被抢光(用户未领取限购码) data.codeEmpty = true; data.cartInfo.limitNotForSale = true; break; case 6: // 开售前,即将开售(用户已领取限购码) data.gotCode = true; data.cartInfo.limitNotForSale = true; break; case 7: // 开售后,用户已经用获得的限购码购买过商品 data.gotCode = true; data.cartInfo.noLimitCode = true; break; default: break; } return data; } /** * 根据设备类型获得限购商品跳转app的url * @param {string} productCode 限购商品码 * @param {string} skn 限购商品skn * @return {string} 限购商品跳转url */ _getLimitCodeUrl(productCode, skn, ua) { let url = 'yohoapp://yoho.app/openwith?limit_product_code=' + productCode + '&product_skn=' + skn; let isIphone = String(ua).indexOf('iPhone') >= 0; let isIpad = ua.indexOf('iPad') >= 0; if (isIphone || isIpad) { let params = {}; params.lp = productCode; url = 'yohobuy://' + helpers.urlFormat('/limitpurchase', params); } return url; } _getShopsInfo(brandId) { if (!brandId) { return Promise.resolve([]); } return api.get({ data: { method: 'app.shop.queryShopsByBrandId', brand_id: _.toString(brandId) }, param: {cache: true} }).then(shops => { if (shops && shops.code === 200) { return this._processShopsInfo(shops.data); } return []; }); } _getPromotionInfo(skn) { return this.get({ data: { method: 'app.product.promotion', product_skn: _.toString(skn) }, params: {cache: true} }).then((result) => { if (result && result.code === 200) { return result.data; } return {}; }); } /** * [单独获取用户收藏商品状态] */ _getFavorite(productId, uid) { if (!uid) { return Promise.resolve(false); } return this.get({ url: 'favorite', data: { method: 'app.favorite.isFavoriteNew', uid: uid, id: productId }, api: singleAPI }).then((result) => { if (result && result.code === 200) { return result.data; } return false; }); } /** * [商品获取数据] pagecache重构 * 可能是已经废弃的代码 */ getProductData(data) { let finalResult; let params = { method: 'app.product.data' }; if (data.id) { // 通过 productId 获取商品详情 Object.assign(params, { product_id: _.toString(data.id) }); } else if (data.productSkn) { // 通过 productSkn 获取商品详情 Object.assign(params, { product_skn: _.toString(data.productSkn) }); } return this.get({ data: params, param: { code: 200, cache: true } }).then(result => { if (!result || result.code === 500 || !result.data) { return {}; } result = result.data; result.goods_id = data.goodsId; return Promise.all([ this._getShopsInfo(_.get(result, 'brand_info.brand_id', 0)), comment.getCommentInfo({ productId: result.product_id }), this._getCommonConsult(), // eslint-disable-line comment.getConsults(result.product_id, 1, 2), bundle.getBundleBySkn(result.product_skn) ]).then((info) => { finalResult = _detailDataPkg(result, data.ua); // eslint-disable-line finalResult.enterStore = info[0]; finalResult.isStudent = data.isStudent; let bundleData = _.get(info[4], 'data', null); /* 套装 */ if (bundleData && _.get(bundleData, 'bundleInfo.discountType', null) === 1) { finalResult.bundleData = { title: '优惠套装', href: helpers.urlFormat('/product/bundle/detail', {skn: result.product_skn, id: result.product_id}), description: '立省¥' + (parseInt(_.get(bundleData, 'bundleInfo.salesPrice', 0), 10) - parseInt(_.get(bundleData, 'bundleInfo.discountPrice', 0), 10)) + '元', productList: productProcess.processProductList(bundleData && bundleData.productList) }; } /* 量贩 */ if (bundleData && _.get(bundleData, 'bundleInfo.discountType', null) === 2) { finalResult.discountBuy = { num: _.get(bundleData, 'bundleInfo.bundleCount', 1), promotionPhrase: _.get(bundleData, 'bundleInfo.promotionPhrase', '') }; } Object.assign(finalResult.feedbacks, info[1]); /* 如果有咨询,显示咨询,否则显示常见问题 */ if (info[3].total) { finalResult.feedbacks.consultsNum = parseInt(info[3].total, 10); Object.assign(finalResult.feedbacks, { commonConsults: false, consultsNum: parseInt(info[3].total, 10), consults: _.take(info[3].list, 2) }); } else if (!_.isEmpty(info[2]) && !_.get(info[1], 'feedbacks.consultsNum', 0)) { Object.assign(finalResult.feedbacks, { commonConsults: true, consultsNum: true, consults: _.take(info[2], 2) }); } /* tar add 161129 SEO 优化使用 */ finalResult.cononical = result.product_url; return finalResult; }); }); } /** * [商品数据格式化] pagecache重构 */ // const _detailDataPkg = (origin, uid, vipLevel, ua) => { _detailDataPkg(origin) { let dest = {}; // 结果输出 // 商品名称 if (!origin.product_name) { dest.feedbacks = {}; return dest; } dest.goodsName = origin.product_name; // 是否是虚拟商品 dest.virtualGoods = (origin.attribute * 1 === 3); // 活动促销短语 origin.market_phrase && (dest.marketPhrase = origin.market_phrase); // 商品促销短语 origin.sales_phrase && (dest.goodsSubtitle = origin.sales_phrase); // 商品标签 if (origin.tags) { let productTags = {}; _.forEach(origin.tags, function(value) { productTags[value] = true; }); dest.tags = productTags; } // 上市期 origin.expect_arrival_time && (dest.periodOfMarket = origin.expect_arrival_time); // 商品咨询 dest.feedbacks = { consults: [], consultsNum: 0 }; let consultParams = { product_id: origin.product_id }; if (_.has(dest, 'feedbacks.consultsNum')) { consultParams.total = dest.feedbacks.consultsNum; dest.feedbacks.consultsUrl = helpers.urlFormat('/product/detail/consults', consultParams); } else { dest.feedbacks.consultsUrl = helpers.urlFormat('/product/detail/consultform', consultParams); } // 商品评价 dest.feedbacks.commentsUrl = helpers.urlFormat('/product/detail/comments', { product_id: origin.product_id }); // 品牌信息 if (origin.brand_info) { let extra = `?productSkn=${origin.product_skn}&brandId=${origin.brand_info.brand_id}`; dest.preferenceUrl = `/product/detail/preference${extra}`; } dest.brandId = origin.brand_id || 0; dest.productSkn = origin.product_skn; dest.isLimitBuy = Number(origin.isLimitBuy); // 1 限购商品, 0 非限购商品 // 商品信息 if (origin.goods_list.length) { let goodsGroup = []; // pagecache重构 _.forEach(origin.goods_list, function(value) { // 商品分组 if (value.images_list) { _.forEach(value.images_list, function(good) { goodsGroup.push({ goodsId: value.goods_id, img: good.image_url }); }); } }); // 商品图:多个 if (goodsGroup.length > 1) { let bannerList = []; _.forEach(goodsGroup, function(value) { bannerList.push({ img: value.img }); }); dest.bannerTop = { list: bannerList }; } else if (goodsGroup[0]) { dest.bannerTop = { img: goodsGroup[0].img }; } } // 悬浮的购物车信息 dest.cartInfo = { cartUrl: helpers.urlFormat('/cart/index/index'), numInCart: 0, goodsInstore: origin.storage_sum }; // 底部简介URL链接 dest.introUrl = '/product/detail/intro/' + origin.product_skn; dest.id = origin.product_id; dest.goodsId = origin.goods_id; dest.isDepositAdvance = origin.is_deposit_advance === 'Y'; // 是否定金预售 dest.isSeckill = origin.is_secKill === 'Y'; // 是否秒杀 dest.isLimitBuy = origin.isLimitBuy; // 是否 限购 dest.isPresale = Boolean(origin.expect_arrival_time); // 是否普通预售 // 自定义 属性 dest.showCoupon = !( dest.isDepositAdvance || dest.isSeckill || dest.isLimitBuy || dest.isPresale ); // 商品有限购、秒杀、定金预售、普通预售 不显示领券 // 20170113 要求关闭商品详情页面领券功能 // dest.showCoupon = false; return dest; } _cartCount(uid, shoppingKey) { return this.get({ data: { method: 'app.Shopping.count', uid: uid, shopping_key: shoppingKey } }).then((result) => { if (result && result.code === 200) { let count = result.data.cart_goods_count || 0; if (count > 99) { count = '99+'; } return count; } return 0; }); } /** * [商品信息格式化异步接口] */ _detailDataPkgAsync(origin, uid, vipLevel, ua) { let dest = {}; // 结果输出 // 用户未登录时 if (!uid) { dest.loginUrl = helpers.urlFormat('/signin.html', { refer: helpers.urlFormat('/product/' + origin.product_skn + '.html') // 商品url改版 }); } // 商品名称 if (!origin.product_name) { dest.feedbacks = {}; return dest; } dest.goodsName = origin.product_name; // 线下店商品展示限制 dest.storeGood = origin.store_show_status === 3 || origin.store_show_status === 4; // 活动促销短语 origin.market_phrase && (dest.marketPhrase = origin.market_phrase); // 商品促销短语 origin.sales_phrase && (dest.goodsSubtitle = origin.sales_phrase); // 促销信息 if (origin.promotionBoList) { let discountList = []; _.forEach(origin.promotionBoList, function(value) { discountList.push({ text: `【${value.promotionType}】${value.promotionTitle}` }); }); discountList.length && (dest.goodsDiscount = { list: discountList }); } // 商品价格 let goodsPrice = { currentPrice: origin.format_sales_price === '0' ? origin.format_market_price : origin.format_sales_price }; if (origin.format_sales_price !== '0' && origin.format_market_price !== origin.format_sales_price) { goodsPrice.previousPrice = origin.format_market_price; } if (origin.student_price) { goodsPrice.studentPrice = origin.student_price; } dest.goodsPrice = goodsPrice; if (origin.is_secKill) { dest.isSecKill = origin.is_secKill; // 判断秒杀字段 } if (origin.is_deposit_advance) { dest.isPresale = Boolean(origin.expect_arrival_time); dest.isDepositAdvance = origin.is_deposit_advance; // 判断定金预售字段 } // 商品返回 YOHO 币 origin.yohoCoinNum && (dest.commodityReturn = origin.yohoCoinNum); // VIP 商品价格 if (origin.vip) { let vipList = []; let levelList = { 银卡: 1, 金卡: 2, 白金: 3 }; _.forEach(origin.vip, function(value) { vipList.push({ level: levelList[value.caption], text: value.price, currentLevel: (levelList[value.caption] === parseInt(vipLevel, 10)) }); }); vipList.length && (dest.vipLevel = { list: vipList }); } // 商品信息 let cartInfo = productProcess.processSkusInfo(origin); let soldOut = (origin.storage_sum === 0) || (cartInfo.totalStorageNum === 0); // status let notForSale = origin.attribute === 2; let preSale = (origin.status === 0 && origin.advance_shelve_time > 0); return new Promise((resolve) => { // 悬浮的购物车信息新增品牌店铺选项storeUrl字段 let storeUrl = ''; if (origin.shop_id) { storeUrl = helpers.urlFormat('/product/shop', { shop_id: origin.shop_id }); } // 悬浮的购物车信息 dest.cartInfo = { cartUrl: helpers.urlFormat('/cart/index/index'), numInCart: 0, goodsInstore: origin.storage_sum, storeUrl: storeUrl }; // 显示加入购物车链接 if (preSale) { // 预售 dest.cartInfo.preSale = true; } else if (soldOut) { // 卖光了 dest.cartInfo.soldOut = true; } else if (notForSale) { // 非卖品 dest.cartInfo.notForSale = true; } else if (origin.is_deposit_advance === 'Y' || origin.is_limit_time_advance === 'Y') { // 定金预售,定金促销 dest.cartInfo.isDepositAdvance = true; } else if (origin.isLimitBuy) { // 限购 Object.assign(dest.cartInfo, cartInfo, { price: dest.goodsPrice.previousPrice ? dest.goodsPrice.previousPrice : '', salePrice: dest.goodsPrice.currentPrice ? dest.goodsPrice.currentPrice : '', }); return this.get({ data: { method: 'app.limitProduct.productStatus', limitProductCode: origin.limitProductCode, uid: uid, product_skn: origin.product_skn }, param: { code: 200, cache: true } }).then((result) => { if (result.data) { if (!result.data.isLimitBuy) { dest.cartInfo.soldOut = true; return resolve(dest); } // 是否开售 let isBeginSale = (result.data.saleStatus === 1); // 限购商品有关的展示状态 let showStatus = 1; origin.showStatus && (showStatus = parseInt(result.data.showStatus, 10)); // 处理限购商品有关的按钮状态 dest = this._procShowStatus(dest, showStatus, isBeginSale); dest.cartInfo.limitProductCode = origin.limitProductCode; dest.cartInfo.limitCodeUrl = this._getLimitCodeUrl(origin.limitProductCode, origin.product_skn, ua); // eslint-disable-line dest.cartInfo.limitProductPay = helpers.urlFormat('/cart/index/orderEnsure'); return resolve(dest); } else { dest.cartInfo.soldOut = true; return resolve(dest); } }); } else if (origin.from === 'detail' && origin.buy_now === 1 && !origin.closeBuyNowButton) { // 显示立即购买和加入购物车两个按钮,closeBuyNowButton 关闭开关 Object.assign(dest.cartInfo, cartInfo, { price: dest.goodsPrice.previousPrice ? dest.goodsPrice.previousPrice : '', salePrice: dest.goodsPrice.currentPrice ? dest.goodsPrice.currentPrice : '', }); dest.showBuyNow = true; dest.cartInfo.addToCartUrl = helpers.urlFormat('/product/buy_' + origin.product_id + '_' + origin.goods_id + '.html'); } else { // 除了上面商品之外的普通商品 Object.assign(dest.cartInfo, cartInfo, { price: dest.goodsPrice.previousPrice ? dest.goodsPrice.previousPrice : '', salePrice: dest.goodsPrice.currentPrice ? dest.goodsPrice.currentPrice : '', }); dest.cartInfo.addToCartUrl = helpers.urlFormat('/product/buy_' + origin.product_id + '_' + origin.goods_id + '.html'); } return resolve(dest); }).then(result => { // 虚拟商品(门票) if (origin.attribute * 1 === 3) { if (result.cartInfo.addToCartUrl) { result.cartInfo.addToCartUrl = false; result.tickets = result.cartInfo.tickets = true; } result.ticketsConfirm = helpers.urlFormat('/cart/index/ticketsConfirm'); // 展览票 // if (origin.product_skn * 1 === SINGLE_TICKETS_SKN) { // result.single = true; // } else { // // 套票 // result.package = true; // } // 购票限制 // result.cartInfo.limit = 4; // 清空活动 result.goodsDiscount = []; } result.id = origin.product_id; result.goodsId = origin.goods_id; if (result.isSecKill === 'Y' && result.cartInfo.totalNum > 0) { result.totalNum = 1; } if (result.storeGood) { result.cartInfo.storeGood = true; } return result; }); } /** * [商品信息的异步数据获取] (优化) */ getNewProductAsyncData(data) { let params = { method: 'app.product.data' }; if (data.productSkn) { // 通过 productSkn 获取商品详情 Object.assign(params, { product_skn: _.toString(data.productSkn) }); } else if (data.id) { // 通过 productId 获取商品详情 Object.assign(params, { product_id: _.toString(data.id) }); } if (data.uid) { params.uid = data.uid; } params.is_student = data.isStudent ? 1 : 0; params.current_vip_level = data.vipLevel; // if (!params.is_student) { // params.current_vip_level = data.vipLevel; // } return this.get({ data: params, param: { code: 200, cache: true } }).then(result => { if (!result || result.code === 500 || !result.data) { return {}; } result = result.data; result.goods_id = data.goodsId; let apiArray = [ this._cartCount(data.uid, data.shoppingKey), this._detailDataPkgAsync(_.assign(result, { from: data.from, closeBuyNowButton: data.closeBuyNowButton }), data.uid, data.vipLevel, data.ua), this._getFavorite(result.product_id, data.uid) ]; if (data.bundleType) { apiArray.push(bundle.getBundleBySkn(data.productSkn)); } return Promise.all(apiArray).then((res) => { let cartCount = res[0]; let finalResult = res[1]; let isFavorite = res[2]; let bundleData = _.get(res[3], 'data', {}); if (cartCount) { finalResult.cartCount = cartCount; } finalResult.isCollect = isFavorite; if (finalResult.cartInfo) { finalResult.cartInfo.isCollect = isFavorite; } finalResult.isStudent = data.isStudent; let discountBuy = _.find(bundleData, bund => _.get(bund, 'bundleInfo.discountType') === 2); /* 量贩 */ if (bundleData && discountBuy) { let minBuyNum = discountBuy.bundleInfo.bundleCount; let isNotEnough = true; // 是否满足量贩购买要求:剩余商品数量大于量贩最小购买量 _.forEach(result.goods_list, goods => { _.forEach(goods.size_list, sizes => { if (sizes.storage_number >= minBuyNum) { isNotEnough = false; } }); }); if (finalResult.cartInfo && isNotEnough) { finalResult.cartInfo.soldOut = isNotEnough; finalResult.cartInfo.addToCartUrl = false; } finalResult.discountBuy = { num: minBuyNum, promotionPhrase: discountBuy.bundleInfo.promotionPhrase, discount: discountBuy.bundleInfo.discount }; } // 2017电子门票不显示区域 // let ticketsProps = finalResult.cartInfo.props; // _.forEach(ticketsProps, function(value) { // if (value.name === '区域') { // value.ticketHide = true; // value.name = ''; // } // }); return finalResult; }); }); } /** * [商品信息的异步数据获取] * 可能已经废弃的代码 */ getProductAsyncData(data) { let finalResult; let params = { method: 'app.product.data' }; if (data.productSkn) { // 通过 productSkn 获取商品详情 Object.assign(params, { product_skn: _.toString(data.productSkn) }); } else if (data.id) { // 通过 productId 获取商品详情 Object.assign(params, { product_id: _.toString(data.id) }); } if (data.uid) { params.uid = data.uid; } params.is_student = data.isStudent ? 1 : 0; params.current_vip_level = data.vipLevel; return this.get({ data: params, param: { code: 200, cache: true } }).then(result => { if (!result || result.code === 500 || !result.data) { return {}; } result = result.data; result.goods_id = data.goodsId; return Promise.all([ this._getPromotionInfo(result.product_skn), this._getFavorite(result.product_id, data.uid) ]).then((res) => { result.promotionBoList = res[0]; let isFavorite = res[1]; return this._detailDataPkgAsync(result, data.uid, data.vipLevel, data.ua).then(pkg => { // eslint-disable-line finalResult = pkg; finalResult.isCollect = isFavorite; if (finalResult.cartInfo) { finalResult.cartInfo.isCollect = isFavorite; } finalResult.isStudent = data.isStudent; return finalResult; }); }); }); } /** * 获取默认咨询列表 */ _getCommonConsult() { let params = { method: 'app.consult.common' }; return this.get({ data: params, param: {code: 200} }).then(result => { let data = {}; if (result.data) { data = result.data; } return data; }); } /** * [根据商品SKN获取商品的简要信息] * @param {[array]} skns [skns] * @return {[type]} */ _productInfoBySkns(skns) { // 调用搜索接口 let param = { method: 'app.search.li', query: skns.join(' '), limit: skns.length, order: 's_t_desc' }; return this.get({ data: param, param: {cache: true} }); } getLimitProductData(uid, limitProductCode) { const param = { method: 'app.limitProduct.limitProductDetail', limitProductCode, uid }; return this.get({data: param}).then(result => { if (!(result && result.data)) { return Promise.reject(result); } let obj = {}; // if (!result.data.hasOwnProperty('attachment')) { // return // } obj.price = result.data.price; obj.name = result.data.productName; obj.releaseDate = `${result.data.saleTime}发售`; obj.banner = helpers.image(result.data.defaultUrl, 750, ''); obj.description = result.data.description; obj.attaches = []; result.data.attachment = result.data.attachment || []; for (let item of result.data.attachment) { if (item.isDefault === 1) { // 排除默认图片 continue; } let attach = {}; switch (item.attachType) { case 1: attach.isImg = true; attach.attachUrl = helpers.image(item.attachUrl, 750, ''); attach.attachName = item.intro; attach.intro = item.intro; break; case 2: attach.isVideo = true; attach.attachUrl = item.attachUrl; attach.img = helpers.image(item.intro, 750, ''); break; case 3: attach.isText = true; attach.intro = item.intro; break; default: break; } attach.orderBy = item.orderBy; obj.attaches.push(attach); } if (obj.attaches.length > 1) { obj.attaches.sort((v1, v2) => { return v2.orderBy - v1.orderBy; }); } return obj; }); } };