|
|
/**
|
|
|
* 商品详情models
|
|
|
* @author: xuqi<qi.xu@yoho.cn>
|
|
|
* @date: 2016/5/6
|
|
|
*/
|
|
|
|
|
|
'use strict';
|
|
|
|
|
|
const Promise = require('bluebird');
|
|
|
const co = Promise.coroutine;
|
|
|
const _ = require('lodash');
|
|
|
const helpers = global.yoho.helpers;
|
|
|
|
|
|
const productAPI = require('./product-api');
|
|
|
|
|
|
const _getProductIntroAsync = (productSkn) => {
|
|
|
return co(function * () {
|
|
|
let result = yield Promise.props({
|
|
|
sizeInfo: productAPI.sizeInfoAsync(productSkn)
|
|
|
});
|
|
|
|
|
|
return result;
|
|
|
})();
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 获得sku商品数据
|
|
|
*/
|
|
|
const _getSkuDataByProductBaseInfo = (data) => {
|
|
|
let totalStorageNum = 0;
|
|
|
let skuGoods = null;// sku商品
|
|
|
let defaultImage = '';// 默认图
|
|
|
let chooseSkuFlag = false; // 选中状态
|
|
|
|
|
|
if (_.isEmpty(_.get(data, 'goods_list', []))) {
|
|
|
return {
|
|
|
totalStorageNum,
|
|
|
skuGoods,
|
|
|
defaultImage
|
|
|
};
|
|
|
}
|
|
|
|
|
|
skuGoods = _.get(data, 'goods_list', []).reduce((acc, cur, pos)=> {
|
|
|
|
|
|
// 如果status为0,即skc下架时就跳过该商品$value['status'] === 0
|
|
|
let goodsGroup = {};
|
|
|
|
|
|
if (_.isEmpty(cur.color_image)) {
|
|
|
return acc;
|
|
|
}
|
|
|
|
|
|
if (cur.images_list) {
|
|
|
// 商品列表
|
|
|
goodsGroup.productSkc = cur.product_skc;
|
|
|
goodsGroup.src = helpers.image(cur.color_image, 40, 40);
|
|
|
goodsGroup.title = `${_.trim(data.product_name)} ${cur.color_name}`;
|
|
|
goodsGroup.name = cur.color_name;
|
|
|
goodsGroup.focus = false;
|
|
|
goodsGroup.total = 0;
|
|
|
goodsGroup.thumbs = [];
|
|
|
goodsGroup.size = [];
|
|
|
}
|
|
|
|
|
|
_.get(cur, 'images_list', []).forEach((good) => {
|
|
|
if (good.image_url) {
|
|
|
goodsGroup.thumbs.push({
|
|
|
url: '',
|
|
|
shower: helpers.image(good.image_url, 420, 560),
|
|
|
img: helpers.image(good.image_url, 75, 100)
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
|
|
|
// 缩略图空,不显示
|
|
|
if (_.isEmpty(goodsGroup.thumbs)) {
|
|
|
return acc;
|
|
|
}
|
|
|
|
|
|
// 默认第一张图片
|
|
|
if (pos === 0) {
|
|
|
defaultImage = helpers.image(cur.color_image, 420, 560);
|
|
|
}
|
|
|
|
|
|
// 商品的尺码列表
|
|
|
_.get(cur, 'size_list', []).forEach((size) => {
|
|
|
if (data.attribute === 3) {
|
|
|
// 虚拟商品,门票默认最大为4,
|
|
|
size.storage_number = size.storage_number > 4 ? 4 : size.storage_number;
|
|
|
}
|
|
|
|
|
|
// 如果status为0,即skc下架时就跳过该商品
|
|
|
if (cur.status === 0) {
|
|
|
size.storage_number = 0;
|
|
|
}
|
|
|
|
|
|
goodsGroup.size.push({
|
|
|
name: size.size_name,
|
|
|
sku: size.product_sku,
|
|
|
num: _.parseInt(size.storage_number),
|
|
|
goodsId: size.size_id
|
|
|
});
|
|
|
|
|
|
// 单个sku商品的总数
|
|
|
goodsGroup.total += _.parseInt(size.storage_number);
|
|
|
|
|
|
if (goodsGroup.total > 0 && !chooseSkuFlag) { // 默认选中该sku商品
|
|
|
goodsGroup.focus = true;
|
|
|
chooseSkuFlag = true;// 选中sku商品
|
|
|
}
|
|
|
|
|
|
totalStorageNum += _.parseInt(size.storage_number);
|
|
|
|
|
|
});
|
|
|
|
|
|
acc.push(goodsGroup);
|
|
|
return acc;
|
|
|
}, []);
|
|
|
|
|
|
if (!_.isEmpty(skuGoods) && !chooseSkuFlag) { // 没有选中一个sku商品,默认选中第一个sku商品
|
|
|
_.head(skuGoods).focus = true;
|
|
|
}
|
|
|
|
|
|
return {
|
|
|
defaultImage: defaultImage,
|
|
|
skuGoods: skuGoods,
|
|
|
totalStorageNum: totalStorageNum
|
|
|
};
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 使sizeBoList id以 sizeAttributeBos id顺序一样
|
|
|
* @param sizeInfoBo
|
|
|
*/
|
|
|
const _sizeInfoBoSort = (sizeInfoBo) => {
|
|
|
if (!sizeInfoBo.sizeBoList || !sizeInfoBo.sizeAttributeBos) {
|
|
|
return {};
|
|
|
}
|
|
|
|
|
|
_.get(sizeInfoBo, 'sizeBoList', []).forEach((sizeBoList, sizek)=> {
|
|
|
let sortAttr = {};
|
|
|
|
|
|
sizeBoList.sortAttributes.forEach(sortAttributes => {
|
|
|
sortAttr[sortAttributes.id] = sortAttributes;
|
|
|
});
|
|
|
|
|
|
sizeInfoBo.sizeBoList[sizek].sortAttributes = sortAttr;
|
|
|
});
|
|
|
|
|
|
_.get(sizeInfoBo, 'sizeBoList', []).forEach((sizeBoList, sizek)=> {
|
|
|
let sortAttr = [];
|
|
|
|
|
|
sizeInfoBo.sizeAttributeBos.forEach(val => {
|
|
|
if (sizeBoList.sortAttributes[val.id]) {
|
|
|
sortAttr.push(sizeBoList.sortAttributes[val.id]);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
sizeInfoBo.sizeBoList[sizek].sortAttributes = sortAttr;
|
|
|
|
|
|
});
|
|
|
|
|
|
return sizeInfoBo;
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 获取尺寸信息
|
|
|
* @param sizeInfo
|
|
|
* @returns {{}}
|
|
|
*/
|
|
|
const _getSizeData = (sizeInfo) => {
|
|
|
|
|
|
// 尺码信息
|
|
|
if (!_.has(sizeInfo, 'sizeInfoBo')) {
|
|
|
return {};
|
|
|
}
|
|
|
|
|
|
sizeInfo.sizeInfoBo = _sizeInfoBoSort(sizeInfo.sizeInfoBo);
|
|
|
|
|
|
let boyReference = _.get(sizeInfo, 'productExtra.boyReference', false);
|
|
|
let girlReference = _.get(sizeInfo, 'productExtra.girlReference', false);
|
|
|
let gender = _.get(sizeInfo, 'productDescBo.gender', 3);
|
|
|
let referenceName = (function() {
|
|
|
if (gender === 3 && boyReference) {
|
|
|
return '参考尺码(男)';
|
|
|
} else if (gender === 3 && girlReference) {
|
|
|
return '参考尺码(女)';
|
|
|
} else {
|
|
|
return '参考尺码';
|
|
|
}
|
|
|
}());
|
|
|
|
|
|
// 判断是否显示参考尺码
|
|
|
let showReference = (boyReference && _.get(sizeInfo, 'sizeInfoBo.sizeBoList[0].boyReferSize', false)) ||
|
|
|
(girlReference && _.get(sizeInfo, 'sizeInfoBo.sizeBoList[0].girlReferSize', false));
|
|
|
|
|
|
if (!_.has(sizeInfo, 'sizeInfoBo.sizeAttributeBos')) {
|
|
|
return {};
|
|
|
}
|
|
|
|
|
|
// 尺码信息头部
|
|
|
let size = {
|
|
|
thead: [{name: '吊牌尺码', id: ''}],
|
|
|
tbody: []
|
|
|
};
|
|
|
|
|
|
// 显示参考尺码
|
|
|
if (showReference) {
|
|
|
size.thead[1] = {name: referenceName, id: ''};
|
|
|
}
|
|
|
|
|
|
_.get(sizeInfo, 'sizeInfoBo.sizeAttributeBos', []).forEach((value) => {
|
|
|
size.thead.push({
|
|
|
name: value.attributeName || ' ',
|
|
|
id: value.id
|
|
|
});
|
|
|
});
|
|
|
|
|
|
_.get(sizeInfo, 'sizeInfoBo.sizeBoList', []).forEach((value) => {
|
|
|
let sizes = [];
|
|
|
|
|
|
// 吊牌尺码
|
|
|
sizes.push(value.sizeName);
|
|
|
|
|
|
// 判断是否显示参考尺码
|
|
|
if (boyReference && (gender === 1 || gender === 3) && showReference) {
|
|
|
sizes.push(_.get(value, 'boyReferSize.referenceName', ' '));
|
|
|
} else if (girlReference && (gender === 2 || gender === 3) && showReference) {
|
|
|
sizes.push(_.get(value, 'girlReferSize.referenceName', ' '));
|
|
|
} else {
|
|
|
if (size.thead[1] && showReference) {
|
|
|
size.thead[1] = {};
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 其他尺码信息
|
|
|
_.get(value, 'sortAttributes', []).forEach(attr => {
|
|
|
sizes.push(_.get(attr, 'sizeValue', ' '));
|
|
|
});
|
|
|
|
|
|
// 尺码信息
|
|
|
size.tbody.push(sizes);
|
|
|
});
|
|
|
|
|
|
// 参考尺码为空
|
|
|
if (_.isEmpty(size.thead[1]) && showReference) {
|
|
|
// 移除这个值
|
|
|
size.thead.splice(1, 1);
|
|
|
}
|
|
|
|
|
|
// 测量方式
|
|
|
if (sizeInfo.sizeImage) {
|
|
|
size.sizeImg = sizeInfo.sizeImage;
|
|
|
}
|
|
|
|
|
|
return size;
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 商品尺码信息
|
|
|
*
|
|
|
* @param productSkn
|
|
|
* @param maxSortId
|
|
|
* @return object
|
|
|
*/
|
|
|
const _getIntroInfo = (productSkn, additionalData)=> {
|
|
|
if (!productSkn) {
|
|
|
return {};
|
|
|
}
|
|
|
|
|
|
let sizeInfo = additionalData.sizeInfo;
|
|
|
|
|
|
if (_.isEmpty(sizeInfo)) {
|
|
|
return {};
|
|
|
}
|
|
|
|
|
|
let result = {};
|
|
|
|
|
|
// 尺寸数据
|
|
|
result.size = _getSizeData(sizeInfo);
|
|
|
|
|
|
return result;
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 详情页数据格式化
|
|
|
* @param origin Object 原始数据
|
|
|
* @return result Object 格式化数据
|
|
|
*/
|
|
|
const _detailDataPkg = (origin) => {
|
|
|
return co(function*() {
|
|
|
if (_.isEmpty(origin) || _.isEmpty(origin)) {
|
|
|
return {};
|
|
|
}
|
|
|
|
|
|
let result = {};
|
|
|
|
|
|
let propOrigin = _.partial(_.get, origin);
|
|
|
|
|
|
// 商品名称
|
|
|
if (!propOrigin('product_name')) {
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
result.name = propOrigin('product_name');
|
|
|
result.skn = propOrigin('product_skn');
|
|
|
result.productId = propOrigin('product_id');
|
|
|
|
|
|
// 商品价格
|
|
|
result.marketPrice = propOrigin('format_market_price');
|
|
|
result.salePrice = propOrigin('format_sales_price');
|
|
|
result.hasOtherPrice = true;
|
|
|
|
|
|
if (result.salePrice === '0') {
|
|
|
delete result.salePrice;
|
|
|
result.hasOtherPrice = false;
|
|
|
}
|
|
|
|
|
|
// 上市期
|
|
|
if (propOrigin('expect_arrival_time')) {
|
|
|
result.arrivalDate = `${propOrigin('expect_arrival_time')}月`;
|
|
|
result.presalePrice = propOrigin('format_sales_price');
|
|
|
delete result.salePrice;
|
|
|
result.hasOtherPrice = false;
|
|
|
}
|
|
|
|
|
|
// sku商品信息
|
|
|
let skuData = _getSkuDataByProductBaseInfo(origin);
|
|
|
|
|
|
// 商品购买状态
|
|
|
let soldOut = !!(propOrigin('status') === 0 || skuData.totalStorageNum === 0);
|
|
|
let notForSale = propOrigin('attribute') === 2; // 非卖品
|
|
|
let virtualGoods = propOrigin('attribute') === 3; // 虚拟商品
|
|
|
|
|
|
if (!soldOut && !notForSale && !virtualGoods) {
|
|
|
result.addToCart = 1;
|
|
|
}
|
|
|
|
|
|
result.colors = skuData.skuGoods;
|
|
|
|
|
|
return result;
|
|
|
})();
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 获取某一个商品详情主页面
|
|
|
*/
|
|
|
const getProductInfoAsync = (pid) => {
|
|
|
return co(function * () {
|
|
|
if (!pid) {
|
|
|
return {};
|
|
|
}
|
|
|
|
|
|
// 获取商品基本信息
|
|
|
let productData = yield productAPI.getProductAsync(pid);
|
|
|
|
|
|
if (_.isEmpty(productData.data)) {
|
|
|
return Promise.reject({
|
|
|
code: 404,
|
|
|
message: 'app.product.data api wrong'
|
|
|
});
|
|
|
}
|
|
|
|
|
|
let productSkn = _.get(productData, 'data.product_skn');
|
|
|
|
|
|
let requestData = yield Promise.all([
|
|
|
_getProductIntroAsync(productSkn), // 商品详细介绍
|
|
|
_detailDataPkg(productData.data) // 商品详细价格
|
|
|
]);
|
|
|
|
|
|
let productDescription = requestData[0];
|
|
|
let productInfo = requestData[1];
|
|
|
|
|
|
let intro = _getIntroInfo(productSkn, productDescription);
|
|
|
|
|
|
return Object.assign(productInfo, intro);
|
|
|
})();
|
|
|
};
|
|
|
|
|
|
module.exports = {
|
|
|
getProductInfoAsync // 获取某一个商品详情主页面
|
|
|
}; |
...
|
...
|
|