Authored by ccbikai

Merge remote-tracking branch 'origin/feature/detailModified'

... ... @@ -100,7 +100,6 @@ try {
// YOHO 后置中间件
app.use(errorHanlder.serverError());
} catch (err) {
console.error(err);
logger.error(err);
}
... ...
... ... @@ -136,7 +136,7 @@ const _getChannelResource = (params) => {
if (result && result.code === 200) {
return resourcesProcess(result.data.list);
} else {
logger.error('首页资源位接口返回状态码 不是 200');
logger.error('index resouce is not 200');
return result;
}
});
... ... @@ -156,7 +156,7 @@ const _getLeftNav = (choosed) => {
if (result && result.code === 200) {
return _processSideBar(result.data, choosed);
} else {
logger.error('侧边栏数据接口返回状态码 不是 200');
logger.error('sidebar code is not 200');
return result;
}
});
... ... @@ -191,7 +191,7 @@ const _getChannelList = () => {
});
return Object.keys(list).length ? list : channelList;
} else {
logger.error('频道选择接口返回状态码 不是 200');
logger.error('channel select code is not 200');
return channelList;
}
});
... ... @@ -210,7 +210,7 @@ const _getChannelBg = () => {
if (result && result.code === 200) {
return result.data.length && result.data[0] && result.data[0].data && result.data[0].data.list[0];
} else {
logger.error('频道选择页背景图接口返回状态码 不是 200');
logger.error('channel select background code is not 200');
return {
src: ''
};
... ...
... ... @@ -29,7 +29,7 @@ const _getResources = (page) => {
if (result && result.code === 200) {
return resourcesProcess(result.data);
} else {
logger.error('星潮教室页面资源位返回 code 不是 200');
logger.error('star class content resource return code no 200');
return [];
}
});
... ... @@ -158,7 +158,7 @@ const getIndexData = () => {
if (result && result.code === 200) {
return _processIndexData(result);
} else {
logger.error('星潮教室首页数据返回 code 不是 200');
logger.error('star class content resource return code no 200');
return {};
}
});
... ... @@ -183,7 +183,7 @@ const getDetailData = (params, uid) => {
return _processGuangData(result.data.list, true);
}
} else {
logger.error('明星专题文章数据返回 code 不是 200');
logger.error('api app.starClass.lastTagArticle code no 200');
return [];
}
});
... ... @@ -227,7 +227,7 @@ const getCollocationListData = (params, uid) => {
if (result && result.code === 200) {
return _processGuangData(result.data.list.artList);
} else {
logger.error('获取星搭配文章列表返回 code 不是 200');
logger.error('getStarClassroomArticleList code no 200');
return [];
}
});
... ...
... ... @@ -10,8 +10,11 @@ const mRoot = '../models';
const headerModel = require('../../../doraemon/models/header'); // 头部model
const detailModel = require(`${mRoot}/detail`); // 商品详情 model
const introModel = require(`${mRoot}/intro`); // 商品尺码信息 model
const preference = require(`${mRoot}/preference`); // 商品偏好 model
const preferenceModel = require(`${mRoot}/preference`); // 商品偏好 model
const detailRelated = require(`${mRoot}/consult-comment`); // 商品评论咨询 model
const _ = require('lodash');
const helpers = global.yoho.helpers;
/**
* 商品基本信息
... ... @@ -34,6 +37,42 @@ exports.index = (req, res, next) => {
uid: uid,
ua: req.get('user-agent') || ''
}).then((result) => {
if (_.isEmpty(result)) {
return next();
}
res.render('detail/detail', {
pageHeader: headerData,
result: result,
page: 'detail',
title: result.goodsName,
pageFooter: true
});
}).catch(next);
};
/**
* 商品基本信息 SKN 进入
* @param {[type]} req [description]
* @param {[type]} res [description]
* @return {[type]} [description]
*/
exports.indexSkn = (req, res, next) => {
if (!req.params[0]) {
return next();
}
let uid = req.user.uid || 0;
let headerData = headerModel.setNav({
navTitle: '商品详情'
});
detailModel.getProductData({
productSkn: req.params[0],
uid: uid,
ua: req.get('user-agent') || ''
}).then((result) => {
if (_.isEmpty(result)) {
return next();
}
res.render('detail/detail', {
pageHeader: headerData,
result: result,
... ... @@ -71,8 +110,8 @@ exports.intro = (req, res, next) => {
* @param {[type]} res [description]
* @return {[type]} [description]
*/
exports.preference = (req, res) => {
preference({
exports.preference = (req, res, next) => {
preferenceModel({
productskn: req.query.productSkn,
yhchannel: req.yoho.channel,
brandId: req.query.brandId
... ... @@ -80,19 +119,24 @@ exports.preference = (req, res) => {
res.render('detail/preference', Object.assign({
layout: false
}, result));
});
}).catch(next);
};
/**
* 购买评价页
*/
exports.comments = (req, res, next) => {
if (!req.query.product_id) {
return next();
}
let headerData = headerModel.setNav({
navTitle: '购买评价'
});
detailRelated.comments(req.query).then((result) => {
res.render('detail/comments', Object.assign({
title: '购买评价',
pageHeader: headerData,
pageFooter: true
}, result));
... ... @@ -103,12 +147,17 @@ exports.comments = (req, res, next) => {
* 购买咨询
*/
exports.consults = (req, res, next) => {
if (!req.query.product_id) {
return next();
}
let headerData = headerModel.setNav({
navTitle: '购买咨询'
});
detailRelated.consults(req.query).then((result) => {
res.render('detail/consults', Object.assign({
title: '购买咨询',
pageHeader: headerData,
pageFooter: true
}, result));
... ... @@ -116,17 +165,46 @@ exports.consults = (req, res, next) => {
};
/**
* 咨询点赞
*/
exports.consultUpvoteOrUseful = (req, res, next) => {
let uid = req.user.uid || 0;
if (!uid) {
return res.json({
code: 401,
message: '用户id为空',
data: helpers.urlFormat('/signin.html', {
refer: helpers.urlFormat('/product/detail/consults', {
product_id: req.body.product_id,
total: req.body.total
})
})
});
}
req.body.isUpvote = /upvote/.test(req.path);
req.body.uid = uid;
detailRelated.upvoteConsult(req.body).then((result) => {
res.json(result);
}).catch(next);
};
/**
* 咨询表单页
*/
exports.consultform = (req, res, next) => {
if (!req.query.product_id) {
return next();
}
let headerData = headerModel.setNav({
navTitle: '我要咨询'
});
if (!req.query.product_id) {
return next();
}
res.render('detail/consult-form', {
title: '我要咨询',
pageHeader: headerData,
productId: req.query.product_id,
formUrl: '/product/detail/consultsubmit',
... ...
... ... @@ -6,8 +6,9 @@
'use strict';
const api = global.yoho.API;
const _ = require('lodash');
const api = global.yoho.API;
const helpers = global.yoho.helpers;
/**
* 获取默认咨询列表
... ... @@ -31,33 +32,6 @@ const _getCommonConsult = () => {
};
/**
* 处理评价列表数据
* @data {[object]} 评价列表原始数据
* @return {[object]}
*/
const _formatCommentsList = (data) => {
let comment = {
list: [],
total: 0
};
if (data.length) {
_.forEach(data, (value) => {
comment.list.push({
userName: value.nickname,
desc: `${value.color_name}/${value.size_name}`,
content: value.content,
time: value.create_time
});
comment.total = value.total;
});
}
return comment;
};
/**
* 处理咨询列表数据
* @data {[object]} 咨询列表原始数据
* @return {[object]}
... ... @@ -84,15 +58,15 @@ const _formatConsultsList = (data) => {
};
/**
* 获取评价数据
* 获取咨询数据
* @id {[number]} 商品id
* @page {[number]} 页码
* @limit {[number]} 每页评价数量
* @limit {[number]} 每页咨询数量
* @return {[object]}
*/
const _getComments = (id, page, limit) => {
const getConsults = (id, page, limit) => {
let params = {
method: 'app.comment.li',
method: 'app.consult.li',
product_id: id,
page: page ? page : 1,
limit: limit ? limit : 300
... ... @@ -103,8 +77,12 @@ const _getComments = (id, page, limit) => {
}).then(result => {
let data = {};
if (result.data) {
Object.assign(data, _formatCommentsList(result.data));
if (result.data && result.data.list) {
Object.assign(data, {
list: _formatConsultsList(result.data.list),
pageTotal: result.data.page_total,
total: result.data.total
});
}
return data;
... ... @@ -112,34 +90,42 @@ const _getComments = (id, page, limit) => {
};
/**
* 获取咨询数据
* @id {[number]} 商品id
* @page {[number]} 页码
* @limit {[number]} 每页咨询数量
* @return {[object]}
* 处理评论数据
*/
const _getConsults = (id, page, limit) => {
let params = {
method: 'app.consult.li',
product_id: id,
page: page ? page : 1,
limit: limit ? limit : 300
let _processComment = (data) => {
let result = {
commentsNum: data.pageResponse.totalCount,
comments: []
};
return api.get('', params, {
code: 200
}).then(result => {
let data = {};
_.forEach(data.pageResponse.list, (item) => {
result.comments.push({
userName: item.userInfo.nickName,
desc: `${item.goods.color_name}/${item.goods.size_name}`,
content: item.content,
time: helpers.dateFormat('YYYY-MM-DD HH:mm:ss', new Date(item.createTime * 1000))
});
});
return result;
};
if (result.data && result.data.list) {
Object.assign(data, {
list: _formatConsultsList(result.data.list),
pageTotal: result.data.page_total,
total: result.data.total
});
/**
* 获取评论信息
*/
let getCommentInfo = (params) => {
return api.get('', Object.assign({
method: 'show.productShareOrderList',
limit: '1',
page: '1',
filterId: '7'
}, params), {
cache: true
}).then((result) => {
if (result.code === 200) {
return _processComment(result.data);
}
return data;
return {};
});
};
... ... @@ -149,14 +135,17 @@ const _getConsults = (id, page, limit) => {
* @return {[object]}
*/
let comments = (params) => {
return _getComments(params.product_id, 1, 60).then(result => {
return getCommentInfo({
productId: params.product_id,
limit: '60'
}).then(result => {
let data = {};
if (result.list && result.list.length) {
if (result.total) {
_.set(data, 'pageHeader.navTitle', `购买评价(${result.total})`);
if (result.comments && result.comments.length) {
if (result.commentsNum) {
_.set(data, 'pageHeader.navTitle', `购买评价(${result.commentsNum})`);
}
data.comments = result.list;
data.comments = result.comments;
}
return data;
... ... @@ -171,7 +160,7 @@ let comments = (params) => {
let consults = (params) => {
return api.all([
_getCommonConsult(),
_getConsults(params.product_id, 1, 60)
getConsults(params.product_id, 1, 60)
]).then(result => {
let data = {
link: `/product/detail/consultform?product_id=${params.product_id}`
... ... @@ -186,10 +175,20 @@ let consults = (params) => {
data.consults = result[1].list;
}
data.showReadMore = result[1].list.length > 2;
return data;
});
};
let upvoteConsult = (params) => {
return api.get('', {
method: params.isUpvote ? 'app.consult.like' : 'app.consult.useful',
id: params.id,
uid: params.uid
});
};
/**
* 购买咨询列表
* @uid {[number]} 用户id
... ... @@ -214,7 +213,10 @@ let addConsult = (uid, productId, content) => {
};
module.exports = {
getCommentInfo, // 商品详情相关,获取评价,来自晒单
comments, // 商品详情相关-购买评价
consults, // 商品详情相关-购买咨询
addConsult // 商品详情相关-添加咨询
addConsult, // 商品详情相关-添加咨询
upvoteConsult, // 咨询点赞
getConsults // 获取咨询
};
... ...
... ... @@ -6,10 +6,14 @@
'use strict';
const api = global.yoho.API;
const _ = require('lodash');
const comment = require('./consult-comment');
const api = global.yoho.API;
const helpers = global.yoho.helpers;
const SINGLE_TICKETS_SKN = 512579596;// 展览票
/**
* 获取用户数据信息
* @param {[string]} uid
... ... @@ -148,6 +152,9 @@ const _detailDataPkg = (origin, uid, vipLevel, ua) => {
dest.goodsName = origin.productName;
// 是否是虚拟商品
dest.virtualGoods = origin.attribute * 1 === 3 ? true : false;
// 用户未登录时
if (!uid) {
let params = {};
... ... @@ -237,47 +244,19 @@ const _detailDataPkg = (origin, uid, vipLevel, ua) => {
dest.periodOfMarket = `${origin.expectArrivalTime}月`;
}
// 促销信息 TODO: 换新接口
if (origin.promotionBoList) {
let discountList = [];
_.forEach(origin.promotionBoList, function(value) {
discountList.push({
text: `【${value.promotionType}${value.promotionTitle}`
});
});
if (discountList.length) {
dest.goodsDiscount = {
list: discountList
};
}
}
// 商品咨询
dest.feedbacks = {
consults: [],
consultsNum: 0
};
if (origin.consultBoWrapper) {
dest.feedbacks.consultsNum = origin.consultBoWrapper.consultTotal;
_.forEach(origin.consultBoWrapper.consultBoList, function(value) {
dest.feedbacks.consults.push({
question: value.ask,
time: value.askTime,
answer: value.answer
});
});
}
let consultParams = {
product_id: origin.id
};
if (_.has(dest, 'feedbacks.consultsNum')) {
consultParams.total = dest.feedbacks.consultsNum;
dest.feedbacks.consultsUrl = helpers.urlFormat('/product/detail/consult', consultParams);
dest.feedbacks.consultsUrl = helpers.urlFormat('/product/detail/consults', consultParams);
} else {
dest.feedbacks.consultsUrl = helpers.urlFormat('/product/detail/consultform', consultParams);
}
... ... @@ -320,13 +299,13 @@ const _detailDataPkg = (origin, uid, vipLevel, ua) => {
if (origin.goodsList) {
let goodsGroup = [],
sizeName = '',
colorList = {},
colorList = [],
sizeList = {},
allSizeList = {},
colorStorageGroup = {},
colorStorageNum = 0;
_.forEach(origin.goodsList, function(value, key) {
_.forEach(origin.goodsList, function(value) {
if (value.status === 0) {
return;
}
... ... @@ -367,7 +346,7 @@ const _detailDataPkg = (origin, uid, vipLevel, ua) => {
};
allSizeList[sizeName] = (allSizeList[sizeName] === null ||
typeof allSizeList[sizeName] === 'undefined') ? build :
typeof allSizeList[sizeName] === 'undefined') ? build :
allSizeList[sizeName];
colorStorageNum += parseInt(size.goodsSizeStorageNum, 10);
... ... @@ -375,13 +354,13 @@ const _detailDataPkg = (origin, uid, vipLevel, ua) => {
});
// 颜色分组
colorList[key] = {
colorList.push({
id: value.colorId,
skcId: value.productSkc,
name: value.colorName,
goodsName: value.goodsName,
colorNum: colorStorageNum
};
});
}
// 缩略图
... ... @@ -399,10 +378,12 @@ const _detailDataPkg = (origin, uid, vipLevel, ua) => {
sizeGroup[0] = {
size: []
};
_.forEach(allSizeList, function(value) {
_.forEach(allSizeList, (value, key) => {
// 默认尺码
sizeGroup[0].size.push({
name: sizeName,
name: key,
sizeNum: _.toNumber(value.storage) > 0 ? true : false,
id: value.id
});
... ... @@ -412,13 +393,16 @@ const _detailDataPkg = (origin, uid, vipLevel, ua) => {
};
// 各个颜色的尺码, 每行显示一个尺码对应的颜色
_.forEach(colorList, function(colorArr) {
colorArr.colorNum = 0;
if (colorStorageGroup[colorArr.skcId] &&
colorStorageGroup[colorArr.skcId][sizeName]) {
colorArr.colorNum = colorStorageGroup[colorArr.skcId][sizeName];
_.forEach(colorList, (colorArr) => {
let tempColorArr = _.cloneDeep(colorArr);
if (colorStorageGroup[tempColorArr.skcId] &&
colorStorageGroup[tempColorArr.skcId][key]) {
tempColorArr.colorNum = colorStorageGroup[tempColorArr.skcId][key];
} else {
tempColorArr.colorNum = 0;
}
colorGroup[i].color.push(colorArr);
colorGroup[i].color.push(Object.assign({}, tempColorArr));
});
colorGroup[i].id = value.id;
... ... @@ -443,6 +427,7 @@ const _detailDataPkg = (origin, uid, vipLevel, ua) => {
++i;
});
// 商品图:多个
if (goodsGroup.length > 1) {
let bannerList = [];
... ... @@ -492,7 +477,7 @@ const _detailDataPkg = (origin, uid, vipLevel, ua) => {
if (origin.isLimitBuy === 'Y') {
// 是否开售
let isBeginSale = (origin.saleStatus !== null && typeof origin.saleStatus !== 'undefined' &&
origin.saleStatus === 1);
origin.saleStatus === 1);
// 限购商品有关的展示状态
let showStatus = 1;
... ... @@ -527,6 +512,31 @@ const _detailDataPkg = (origin, uid, vipLevel, ua) => {
dest.introUrl = '/product/detail/intro/' + origin.erpProductId;
dest.id = origin.id;
// 虚拟商品(门票)
if (origin.attribute * 1 === 3) {
dest.tickets = true;
dest.ticketsConfirm = helpers.urlFormat('/cart/index/ticketsConfirm');
// 展览票
if (origin.erpProductId * 1 === SINGLE_TICKETS_SKN) {
dest.single = true;
} else {
// 套票
dest.package = true;
}
// 购票限制
dest.cartInfo.limit = 4;
// 清空活动
dest.goodsDiscount = [];
// 来自登录页,自动弹出选择框
// if (isset($_GET['product_type']) && $_GET['product_type'] == 'ticket') {
// $result['showPannel'] = true;
// }
}
return dest;
};
... ... @@ -560,13 +570,44 @@ let _getPromotionInfo = (skn) => {
});
};
/**
* 获取默认咨询列表
*/
const _getCommonConsult = () => {
let params = {
method: 'app.consult.common'
};
return api.get('', params, {
code: 200
}).then(result => {
let data = {};
if (result.data) {
data = result.data;
}
return data;
});
};
let getProductData = (data) => {
let finalResult;
let params = {
productId: _.toString(data.id),
method: 'h5.product.data'
};
if (data.id) { // 通过 productId 获取商品详情
Object.assign(params, {
productId: _.toString(data.id)
});
} else if (data.productSkn) { // 通过 productSkn 获取商品详情
Object.assign(params, {
product_skn: _.toString(data.productSkn)
});
}
if (!_.isEmpty(data.uid)) {
params.uid = data.uid;
}
... ... @@ -577,12 +618,42 @@ let getProductData = (data) => {
return api.get('', params, {
cache: true
}).then(result => {
return Promise.all([_getShopsInfo(result.brandId), _getPromotionInfo(result.erpProductId)]).then((info) => {
if (result.code === 500) {
return {};
}
return Promise.all([
_getShopsInfo(result.brandId),
_getPromotionInfo(result.erpProductId),
comment.getCommentInfo({
productId: result.id
}),
_getCommonConsult(),
comment.getConsults(result.id, 1, 2)
]).then((info) => {
result.promotionBoList = info[1];
finalResult = _detailDataPkg(result, data.uid, data.vipLevel, data.ua);
finalResult.enterStore = info[0];
Object.assign(finalResult.feedbacks, info[2]);
/* 如果有咨询,显示咨询,否则显示常见问题 */
if (info[4].total) {
finalResult.feedbacks.consultsNum = parseInt(info[4].total, 10);
Object.assign(finalResult.feedbacks, {
commonConsults: false,
consultsNum: parseInt(info[4].total, 10),
consults: _.take(info[4].list, 2)
});
} else if (!_.isEmpty(info[3]) && !_.get(info[2], 'feedbacks.consultsNum', 0)) {
Object.assign(finalResult.feedbacks, {
commonConsults: true,
consultsNum: true,
consults: _.take(info[3], 2)
});
}
return finalResult;
});
... ...
... ... @@ -75,9 +75,9 @@ const getSizeInfo = (sizeInfo) => {
dest.sizeInfo.detail.list = [];
// 参考尺码
let boyReference = !_.isEmpty(sizeInfo.productExtra.boyReference);
let girlReference = !_.isEmpty(sizeInfo.productExtra.girlReference);
let gender = !_.isEmpty(sizeInfo.productDescBo.gender) ? sizeInfo.productDescBo.gender : 3;
let boyReference = sizeInfo.productExtra.boyReference;
let girlReference = sizeInfo.productExtra.girlReference;
let gender = sizeInfo.productDescBo.gender ? sizeInfo.productDescBo.gender : 3;
let referenceName = '参考尺码';
if ((gender === 1 && boyReference) || (gender === 2 && girlReference)) {
... ... @@ -102,12 +102,14 @@ const getSizeInfo = (sizeInfo) => {
if (!_.isEmpty(sizeInfo.sizeInfoBo.sizeAttributeBos)) {
// [{param: attrName}] th
let sizeNameList = [];
temp = {};
temp.param = '吊牌尺码';
sizeNameList.push(temp);
// {id: [{param: str},......]} sizeBoGroup[id][0] 属性名, sizeBoGroup[id][index] 属性值
let sizeBoGroup = {};
_.forEach(sizeInfo.sizeInfoBo.sizeAttributeBos, function(attr) {
... ... @@ -126,13 +128,11 @@ const getSizeInfo = (sizeInfo) => {
if (boyReference && (gender === 1 || gender === 3)) {
temp = {};
temp.param = _.isEmpty(value.boyReferSize.referenceName) ?
' ' : value.boyReferSize.referenceName;
temp.param = value.boyReferSize.referenceName || '';
referenceList.push(temp);
} else if (girlReference && (gender === 2 || gender === 3)) {
temp = {};
temp.param = _.isEmpty(value.girlReferSize.referenceName) ?
' ' : value.girlReferSize.referenceName;
temp.param = value.girlReferSize.referenceName || '';
referenceList.push(temp);
} else {
showReference = false;
... ... @@ -140,7 +140,7 @@ const getSizeInfo = (sizeInfo) => {
_.forEach(value.sortAttributes, function(attr) {
temp = {};
temp.param = _.isEmpty(attr.sizeValue) ? ' ' : attr.sizeValue;
temp.param = attr.sizeValue || ' ';
sizeBoGroup[attr.id].push(temp);
});
});
... ... @@ -149,6 +149,7 @@ const getSizeInfo = (sizeInfo) => {
dest.sizeInfo.detail.list[0] = {};
dest.sizeInfo.detail.list[0].params = sizeNameList;
if (showReference) {
dest.sizeInfo.detail.list[1] = {};
dest.sizeInfo.detail.list[1].params = referenceList;
}
_.forEach(sizeBoGroup, function(value) {
... ... @@ -302,15 +303,15 @@ const getSizeInfo = (sizeInfo) => {
dest.productDetail.enTitle = 'DETAILS';
dest.productDetail.desc = productIntro.replace(/\r\n\t/g, '').
replace(/<\/p>/g, '').
replace(/<img src=/g, '<img class="lazy" src="data:image/gif;' +
'base64,R0lGODlhAQABAJEAAAAAAP///93d3f///yH5BAEAAAMALAAAAAABAAEAAAICVAEAOw=="' +
' data-original=').
replace(/<img border="0" src=/g, '<img border="0" class="lazy" ' +
'src="data:image/gif;base64,' +
'R0lGODlhAQABAJEAAAAAAP///93d3f///yH5BAEAAAMALAAAAAABAAEAAAICVAEAOw=="' +
' data-original=').
replace(/.jpg/g, '.jpg?imageMogr2/thumbnail/750x/quality/90');
replace(/<\/p>/g, '').
replace(/<img src=/g, '<img class="lazy" src="data:image/gif;' +
'base64,R0lGODlhAQABAJEAAAAAAP///93d3f///yH5BAEAAAMALAAAAAABAAEAAAICVAEAOw=="' +
' data-original=').
replace(/<img border="0" src=/g, '<img border="0" class="lazy" ' +
'src="data:image/gif;base64,' +
'R0lGODlhAQABAJEAAAAAAP///93d3f///yH5BAEAAAMALAAAAAABAAEAAAICVAEAOw=="' +
' data-original=').
replace(/.jpg/g, '.jpg?imageMogr2/thumbnail/750x/quality/90');
}
// 清空变量,释放内存
... ...
... ... @@ -229,7 +229,7 @@ const _getResources = (page, channel) => {
if (result && result.code === 200) {
return resourcesProcess(result.data);
} else {
logger.error('SALE 页面资源位返回 code 不是 200');
logger.error('SALE content resource code no 200');
return [];
}
});
... ... @@ -250,7 +250,7 @@ const _getBreakingSort = (yhChannel) => {
if (result && result.code === 200) {
return _processBreakingSort(result.data);
} else {
logger.error('断码区分类接口返回 code 不是 200');
logger.error('api app.sale.getBreakingSort code no 200');
return {};
}
});
... ... @@ -268,7 +268,7 @@ const getSearchData = (params, uid) => {
showSale: false
});
} else {
logger.error('SALE 商品搜索返回 code 不是 200');
logger.error('api SALE product search code no 200');
return [];
}
}),
... ... @@ -276,7 +276,7 @@ const getSearchData = (params, uid) => {
if (result && result.code === 200) {
return result.data.vip_info ? camelCase(result.data.vip_info) : {};
} else {
logger.error('获取用户信息返回 code 不是 200');
logger.error('api get user info code no 200');
return {};
}
})
... ... @@ -296,7 +296,7 @@ const getFilterData = (params) => {
hideSort: params.saleType === '1'
});
} else {
logger.error('SALE 商品搜索返回 code 不是 200');
logger.error('SALE search product code no 200');
return [];
}
});
... ... @@ -328,12 +328,12 @@ const getVipData = (channel) => {
const getBreakCodeData = (params) => {
params = params || {};
return Promise.all([_getResources('breakCode', params.yhChannel), _getBreakingSort(params.yhChannel)])
.then((result) => {
return {
content: result[0],
nav: result[1]
};
});
.then((result) => {
return {
content: result[0],
nav: result[1]
};
});
};
/**
... ... @@ -350,7 +350,7 @@ const getDiscountData = (yhChannel) => {
list: _processDiscount(result.data)
};
} else {
logger.error('折扣专场专题列表返回 code 不是 200');
logger.error('api discount list code no 200');
return {};
}
});
... ... @@ -383,7 +383,7 @@ const getDiscountDetailData = (id, yhChannel) => {
}
};
} else {
logger.error('折扣专场专题详情返回 code 不是 200');
logger.error('discount detail code no 200');
return {};
}
});
... ...
... ... @@ -28,13 +28,18 @@ const recommendForYou = require(`${cRoot}/recommend-for-you`);
// /pro_136349_455445/HEARTSOFARMianMaShuJiaoXiuXianKuPS1684.html
router.get(/\/pro_([\d]+)_([\d]+)\/(.*)/, detail.index); // 商品详情页
// /show_51047967.html
router.get(/\/show_([\d]+)/, detail.indexSkn); // 商品详情页 SKN 进入
router.get('/detail/intro/:productskn', detail.intro); // 商品内嵌页
router.get('/detail/preference', detail.preference); // 为你优选
router.get('/detail/consults', detail.consults); // 商品咨询页
router.get('/detail/consultform', auth, detail.consultform); // 商品咨询表单页
router.get('/detail/comments', detail.comments);
router.get('/detail/comments', detail.comments); // 商品评价
router.post('/detail/consultsubmit', auth, detail.consultsubmit); // 商品咨询提交接口
router.post('/detail/consultupvote', detail.consultUpvoteOrUseful); // 商品咨询提交接口
router.post('/detail/consultuseful', detail.consultUpvoteOrUseful); // 商品咨询提交接口
router.get('/sale', sale.index);
router.get('/sale/discount', sale.discount);
router.get('/sale/discount/detail', sale.discountDetail);
... ...
... ... @@ -135,8 +135,7 @@
<a href="{{cartUrl}}" class="num-incart iconfont"><span class="num-tag hide"></span>&#xe62c;</a>
{{#if addToCartUrl}}
<!-- <a id="addtoCart" href="{{addToCartUrl}}" class="addto-cart">加入购物车</a> -->
<a id="addtoCart" href="javascript:;" class="addto-cart">加入购物车</a>
<a id="addtoCart" href="javascript:;" class="addto-cart">{{#if ../tickets}}立即购买{{else}}加入购物车{{/if}}</a>
{{/if}}
{{#if soldOut}}
... ... @@ -183,5 +182,16 @@
<input type="hidden" name="loginUrl" id="loginUrl" value="{{.}}">
{{/loginUrl}}
{{#if tickets}}
<form id="buyNowForm" method="post" action="{{ticketsConfirm}}">
<input type="hidden" name="productSku" id="productSku">
<input type="hidden" name="buyNumber" id="buyNumber">
</form>
{{/if}}
{{#if showPannel}}
<input type="hidden" id="showPannel" value="1">
{{/if}}
</div>
{{/ result}}
... ...
<ul id="nav-tab" class="nav-tab clearfix">
<li class="comment-nav tap-hightlight">商品评价(<span class="comments-num">{{commentsNum}}</span>)</li>
<li class="consult-nav tap-hightlight">购买咨询(<span class="consults-num">{{consultsNum}}</span>)</li>
{{#if commonConsults}}
<li class="consult-nav tap-hightlight">常见问题</li>
{{^}}
<li class="consult-nav tap-hightlight">购买咨询(<span class="consults-num">{{consultsNum}}</span>)</li>
{{/if}}
</ul>
<div id="feedback-content" >
<div class="comment-content content ">
{{#if commentsNum}}
<div class="comment-content-main content-main">
{{# comments}}
<span class="user-name">
{{userName}}
</span>
<div class="comment-content-main content-main">
{{# comments}}
<span class="user-name">
{{userName}}
</span>
<span class="goods-spec">
购买了{{desc}}
</span>
<p class="detail-content">
{{content}}
</p>
<p class="detail-content">
{{content}}
</p>
<span class="comment-time">
{{time}}
</span>
{{/ comments}}
</div>
<a class="comment-content-footer tap-hightlight" href="{{commentsUrl}}">
{{/ comments}}
</div>
<a class="comment-content-footer tap-hightlight" href="{{commentsUrl}}">
查看更多
<span class="iconfont">&#xe604;</span>
</a>
</a>
{{^}}
<div class="comment-content-main content-main no-item">
<span class="iconfont">&#xe63d;</span>暂无评论
</div>
<div class="comment-content-main content-main no-item">
<span class="iconfont">&#xe63d;</span>暂无评论
</div>
{{/if}}
</div>
<div class="consult-content content hide ">
{{#if consultsNum}}
<div class="consult-content-main content-main">
{{# consults}}
<div class="question">
<span class="iconfont">&#xe644;</span>
<p>
{{question}}<br>
<span class="time">{{time}}</span>
</p>
</div>
<div class="consult-content-main content-main">
{{# consults}}
<div class="question">
<span class="iconfont">&#xe644;</span>
<p>
{{question}}<br>
<span class="time">{{time}}</span>
</p>
</div>
<div class="answer">
<span class="iconfont">&#xe642;</span>
<p>{{answer}}</p>
<div class="answer">
<span class="iconfont">&#xe642;</span>
<p>{{answer}}</p>
</div>
{{/ consults}}
</div>
{{/ consults}}
</div>
<a class="consult-content-footer tap-hightlight" href="{{consultsUrl}}">
查看更多
<span class="iconfont">&#xe604;</span>
</a>
<a class="consult-content-footer tap-hightlight" href="{{consultsUrl}}">
查看更多
<span class="iconfont">&#xe604;</span>
</a>
{{else}}
<div class="consult-content-main content-main no-item">
<span class="iconfont">&#xe63f;</span>暂无咨询
</div>
<div class="consult-content-main content-main no-item">
<span class="iconfont">&#xe63f;</span>暂无咨询
</div>
<div class="consult-content-footer tap-hightlight">
<a href="{{consultsUrl}}">
我要咨询
<span class="iconfont">&#xe604;</span></a>
</div>
<div class="consult-content-footer tap-hightlight">
<a href="{{consultsUrl}}">
我要咨询
<span class="iconfont">&#xe604;</span></a>
</div>
{{/if}}
</div>
</div>
... ...
... ... @@ -33,9 +33,9 @@ module.exports = {
useOneapm: false,
useCache: false,
memcache: {
master: ['192.168.102.222:12111'],
slave: ['192.168.102.222:12111'],
session: ['192.168.102.222:12111'],
master: ['192.168.102.205:12111'],
slave: ['192.168.102.205:12111'],
session: ['192.168.102.205:12111'],
timeout: 1000,
retries: 0
},
... ... @@ -63,7 +63,6 @@ module.exports = {
handleExceptions: true
},
udp: { // send by udp
measurement: 'yohobuywap_node_log',
level: 'debug', // logger level
host: '192.168.102.162', // influxdb host
port: '4444' // influxdb port
... ... @@ -90,9 +89,9 @@ if (isProduction) {
service: 'http://service.yoho.yohoops.org/'
},
memcache: {
master: ['memcache1.yohoops.org:12111', 'memcache2.yohoops.org:12111'],
slave: ['memcache1.yohoops.org:12112', 'memcache2.yohoops.org:12112'],
session: ['memcache1.yohoops.org:12111', 'memcache2.yohoops.org:12111'],
master: ['memcache1.yohoops.org:12111', 'memcache2.yohoops.org:12111', 'memcache3.yohoops.org:12111'],
slave: ['memcache1.yohoops.org:12112', 'memcache2.yohoops.org:12112', 'memcache3.yohoops.org:12112'],
session: ['memcache1.yohoops.org:12111', 'memcache2.yohoops.org:12111', 'memcache3.yohoops.org:12111'],
timeout: 1000,
retries: 0
},
... ...
{{#cartInfo}}
<div class="chose-panel">
<div class="main">
<div class="infos">
<div class="infos {{#if ../tickets}}tickets-info{{/if}}">
<div class="basic-info" >
{{#thumbs}}
<img class="thumb {{#unless @first}}hide{{/unless}}" src={{image img 60 60}}>
... ... @@ -18,7 +18,7 @@
</div>
<div class="chose-items">
<div class="color-list block-list">
<span>颜色</span>
<span>{{#if ../tickets}}日期{{else}}颜色{{/if}}</span>
{{# colors}}
<ul id="{{id}}" data-index="{{@index}}" class="size-row clearfix {{#unless @first}}hide{{/unless}}">
{{# color}}
... ... @@ -29,8 +29,8 @@
</ul>
{{/ colors}}
</div>
<div class="size-list block-list">
<span>尺码</span>
<div class="size-list block-list {{#if ../single}}hide{{/if}}">
<span>{{#if ../tickets}}区域{{else}}尺码{{/if}}</span>
{{# sizes}}
<ul class="size-row clearfix {{#unless @first}}hide{{/unless}}">
{{# size}}
... ... @@ -41,7 +41,7 @@
</ul>
{{/ sizes}}
</div>
<p>
<div class="num">
<span>数量</span>
<div class="clearfix">
... ... @@ -55,13 +55,16 @@
</div>
<span class="left-num"></span>
<input id="left-num" type="hidden" value="0">
<input id="limitNum" type="hidden" value="{{limit}}">
</div>
</div>
</div>
<div class="btn-wrap">
<button id="chose-btn-sure" class="btn btn-sure">加入购物车</button>
<button id="chose-btn-sure" class="btn btn-sure">{{#if ../tickets}}立即购买{{else}}加入购物车{{/if}}</button>
</div>
</div>
</div>
{{/cartInfo}}
<input id="promotionId" type="hidden" value="{{promotionId}}">
\ No newline at end of file
<input id="promotionId" type="hidden" value="{{promotionId}}">
<input id="single" type="hidden" value="{{single}}">
\ No newline at end of file
... ...
... ... @@ -100,7 +100,7 @@
"yoho-jquery": "^2.2.4",
"yoho-jquery-lazyload": "^1.9.7",
"yoho-mlellipsis": "0.0.3",
"yoho-node-lib": "0.0.31",
"yoho-node-lib": "0.0.32",
"yoho-swiper": "^3.3.1"
}
}
... ...
... ... @@ -10,6 +10,7 @@
// 增加init函数,异步请求的接口需要重新初始化一下选择列表
// 异步渲染的模板统一插入 #chose-panel ,兼容页面多个选择框
var $ = require('yoho-jquery'),
tip = require('../plugin/tip'),
loading = require('../plugin/loading');
... ... @@ -37,7 +38,14 @@ var $chosePanel = $('#chose-panel'),
$choseArea,
$cartBar,
$soonSoldOut = $('.soonSoldOut-tag'),
$yohoPage = $('.yoho-page');
$yohoPage = $('.yoho-page'),
// 门票 限购数量
ticketsLimit = $('#limitNum').val() || 0,
single = $('#single').val() || 0,
$productSku = $('#productSku'),
$buyNumber = $('#buyNumber'),
$buyNowForm = $('#buyNowForm');
// 购物车编辑标相关变量
var isEdit,
... ... @@ -66,7 +74,6 @@ function init() {
hasChooseColor = false;
hasChooseSize = false;
$curSizeBlock = null;
queryString = $.queryString();
$imgsThumb = $('.chose-panel').find('.thumb');
$choseArea = $('.chose-panel .main .chose-items');
... ... @@ -126,7 +133,35 @@ function removePannel() {
}
}
// 检查门票选择
function checkTickets() {
if (!hasChooseColor && !hasChooseSize) {
if (single) {
tip.show('请选择日期~');
} else {
tip.show('请选择日期和区域~');
}
return false;
} else if (!hasChooseColor) {
tip.show('请选择日期~');
return false;
} else if (!hasChooseSize && !single) {
tip.show('请选择区域~');
return false;
}
return true;
}
function checkColorSizeNum() {
if (ticketsLimit) {
// 门票
if (!checkTickets()) {
return;
}
}
if (!hasChooseColor && !hasChooseSize) {
tip.show('请选择颜色和尺码~');
return false;
... ... @@ -140,8 +175,6 @@ function checkColorSizeNum() {
return true;
}
function show(html, cb) {
if (html) {
$chosePanel.html(html);
... ... @@ -174,7 +207,7 @@ function updateConformButtonClassAndText() {
$chosed = $allChoseItems.find('.chosed');
if ($chosed.closest('.zero-stock').length === 2) {
$('#chose-btn-sure').css('background-color', '#c0c0c0').html('已售罄');
} else if (limitProductCode) {
} else if (limitProductCode || ticketsLimit) {
$('#chose-btn-sure').css('background-color', '#eb0313').html('立即购买');
} else {
$('#chose-btn-sure').css('background-color', '#eb0313').html(isEdit ? '确认' : '加入购物车');
... ... @@ -184,7 +217,14 @@ function updateConformButtonClassAndText() {
// 显示剩余件数
function displayGoodNum(curGoodNum) {
// 数量大于0
// 门票限购
if (ticketsLimit) {
$allChoseItems.find('.num .left-num').html('限购' + ticketsLimit + '件');
$leftNum.val(curGoodNum);
return;
}
// 数量大于
if (curGoodNum > 0) {
if ($soonSoldOut.length > 0) {
$allChoseItems.find('.num .left-num').html('即将售罄');
... ... @@ -204,6 +244,7 @@ function displayGoodNum(curGoodNum) {
// 老的选中尺码去掉勾选,新的选中尺码加上勾选
function changeSizeChosed(newSizeIndex) {
var sizes,
queryString,
i;
if (curColorIndex && $curSizeBlock && $curSizeBlock.length > 0) {
... ... @@ -247,6 +288,38 @@ function changeColorChosed(newColorIndex) {
return 0;
}
// 添加门票
function addTickets(productSku, buyNumber) {
var data = {
productSku: productSku,
buyNumber: buyNumber
};
// 校验电子票
$.ajax({
url: '/cart/index/checkTickets',
dataType: 'json',
data: data,
type: 'post',
success: function(addRestult) {
if (addRestult.code !== 200) {
if (addRestult.code === 401) {
window.location.href = '//m.yohobuy.com/signin.html?refer=' + window.location.href;
}
tip.show(addRestult.message);
} else {
$productSku.val(productSku);
$buyNumber.val(buyNumber);
$buyNowForm.submit();
}
},
error: function() {
tip.show('网络异常~');
}
});
}
init();
... ... @@ -327,6 +400,20 @@ $yohoPage.on('touchstart', '.color-list .block', function() {
// 设置按钮的样式和文字
updateConformButtonClassAndText();
// 展览票
if (ticketsLimit && single) {
// 选中日期
$curSizeBlock = $('.size-list .size-row .block').eq(index + 1);
$curSizeBlock.addClass('chosed');
// 显示剩余数量
displayGoodNum($curColorBlock.data('num'));
hasChooseSize = true;
return false;
}
}).on('touchstart', '.size-list .block', function() {
var $this = $(this),
index,
... ... @@ -391,7 +478,7 @@ $yohoPage.on('touchstart', '.btn-minus', function() {
return;
}
if (num === 1 || (leftNum - 0) === 0) {
if (num === 1 || leftNum - 0 === 0) {
tip.show('您选择的数量不能为零~');
return;
}
... ... @@ -402,9 +489,10 @@ $yohoPage.on('touchstart', '.btn-minus', function() {
$num.val(num - 1);
}).on('touchstart', '.btn-plus', function() {
var num = parseInt($num.val(), 10);
var num = parseInt($num.val(), 10),
maxTips = ticketsLimit ? '每人只可购买' + ticketsLimit + '张当日门票' : '您选择的数量超过了最大库存量~';
leftNum = $('#left-num').val();
leftNum = ticketsLimit || $('#left-num').val();
if (!checkColorSizeNum()) {
return;
... ... @@ -416,7 +504,7 @@ $yohoPage.on('touchstart', '.btn-minus', function() {
// TODO:库存数验证
if (num > leftNum - 1) {
tip.show('您选择的数量超过了最大库存量~');
tip.show(maxTips);
return;
}
$num.val(num + 1);
... ... @@ -458,9 +546,18 @@ $yohoPage.on('touchstart', '.btn-minus', function() {
return false;
}
confirming = true;
if (!ticketsLimit) {
confirming = true;
}
loading.showLoadingMask();
// 立即购买门票
if (ticketsLimit) {
addTickets(productSku, buyNumber);
return;
}
// 针对是否处于编辑模式设置不同的url和需要post的数据
if (isEdit) {
cartGoodData = {
... ...
... ... @@ -41,6 +41,7 @@ var navtabEle = document.getElementById('nav-tab'),
$('#feedback-content .consult-content').removeClass('hide');
}
$('.goods-consults .consult-item:lt(2)').removeClass('hide');
}());
if (navtabHammer) {
... ... @@ -91,8 +92,7 @@ if ($('.goods-consults-page').length > 0) {
if (readmoreHammer) {
readmoreHammer.on('tap', function() {
$('.readmore').hide();
$('.goods-consults.customer-consults').removeClass('customer-consults');
$('.goods-consults').find('.consult-item').removeClass('hide');
return false;
});
}
... ...
... ... @@ -47,28 +47,27 @@ function hiddenTips($ele) {
// }
// }
function wrapElements(selector, count) {
var elArr = null;
// function wrapElements(selector, count) {
// var elArr = null;
$(selector).each(function(idx) {
elArr = $(selector).slice(idx, idx + count);
// $(selector).each(function(idx) {
// elArr = $(selector).slice(idx, idx + count);
if (elArr.length === count && idx % count === 0) {
$(elArr).wrapAll($('<div class="js-wraper"></div>'));
}
});
}
// if (elArr.length === count && idx % count === 0) {
// $(elArr).wrapAll($('<div class="js-wraper"></div>'));
// }
// });
// }
function search() {
if (searching || end) {
if (searching || end || !introUrl) {
return;
}
searching = true;
// alert($('#reference-swiper-container .swiper-wrapper').width());
loading.showLoadingMask();
$.ajax({
... ... @@ -98,7 +97,7 @@ function search() {
// if (!isFlexSupport()) {
// $('.detail .column').removeClass('column').addClass('oldbox');
// }
wrapElements('.detail .column', 2);
// wrapElements('.detail .column', 2);
searching = false;
end = true;
loading.hideLoadingMask();
... ...
... ... @@ -56,26 +56,28 @@ $basicBtnC: #eb0313;
&.table {
width: 100%;
.js-wraper {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
}
overflow: hidden;
.column {
display: flex;
flex-basis: 49.9%;
align-items: center;
box-sizing: border-box;
padding: 6px 3%;
width: 49.9%;
border: 1px solid #fff;
background-color: $tableCellC;
word-wrap: break-word;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
font-size: 24px;
}
.column:nth-child(2n+1) {
float: left;
}
.column:nth-child(2n+2) {
float: right;
}
.oldbox {
float: left;
overflow: hidden;
... ... @@ -284,7 +286,7 @@ $basicBtnC: #eb0313;
.limit-sale {
position: absolute;
top: 50%;
right: 84px;
right: 24px;
margin-top: -24px;
padding: 4px 20px;
height: 48px;
... ... @@ -384,13 +386,13 @@ $basicBtnC: #eb0313;
text-align: left;
.vip-img {
background: resolve('product/silver.png') no-repeat;
background: resolve("product/silver.png") no-repeat;
}
}
&:nth-child(2) {
.vip-img {
background: resolve('product/golden.png') no-repeat;
background: resolve("product/golden.png") no-repeat;
}
}
... ... @@ -398,7 +400,7 @@ $basicBtnC: #eb0313;
text-align: right;
.vip-img {
background: resolve('product/platinum.png') no-repeat;
background: resolve("product/platinum.png") no-repeat;
}
}
}
... ... @@ -707,52 +709,53 @@ $basicBtnC: #eb0313;
a {
display: inline-block;
}
&.num-incart {
color: #444;
font-size: 47px;
}
.num-incart {
position: relative;
color: #444;
font-size: 47px;
}
&.favorite {
color: #ccc;
font-size: 34px;
}
.favorite {
color: #ccc;
font-size: 34px;
background-color: transparent;
}
&.favorite.liked {
color: $basicBtnC;
}
.favorite.liked {
color: $basicBtnC;
}
&.addto-cart,
&.sold-out {
margin: 0 100px 0 115px;
width: 260px;
height: 80px;
background-color: $basicBtnC;
color: #fff;
text-align: center;
font-size: 32px;
line-height: 80px;
}
.addto-cart,
.sold-out {
margin: 0 100px 0 115px;
width: 260px;
height: 80px;
background-color: $basicBtnC;
color: #fff;
text-align: center;
font-size: 32px;
line-height: 80px;
}
&.sold-out {
background-color: #f58189;
}
.sold-out {
background-color: #ccc;
}
.num-tag {
position: absolute;
top: 0;
left: 48px;
right: -15px;
display: block;
width: 72px;
height: 72px;
width: 30px;
height: 30px;
border-radius: 50%;
background: $basicBtnC;
color: #fff;
text-align: center;
font-size: 40px;
line-height: 72px;
transform: scale(0.5);
font-size: 20px;
line-height: 30px;
&.hide {
display: none;
... ... @@ -768,3 +771,7 @@ $basicBtnC: #eb0313;
top: 40%;
}
}
iframe {
display: none;
}
... ...
... ... @@ -4,10 +4,8 @@
padding-bottom: 20px;
.service {
margin-left: 50px;
width: 494px;
height: 28px;
background: resolve('product/service.png') no-repeat;
background: resolve("product/service.png") no-repeat;
background-size: cover;
}
... ...