Authored by 郭成尧

merge-master

Showing 79 changed files with 909 additions and 209 deletions
... ... @@ -51,6 +51,11 @@ app.set('etag', false);
app.enable('trust proxy');
// 请求限制中间件
if (!app.locals.devEnv) {
app.use(require('./doraemon/middleware/limiter'));
}
// 指定libray目录
global.utils = path.resolve('./utils');
... ...
'use strict';
const _ = require('lodash');
const cache = global.yoho.cache.master;
exports.index = (req, res) => {
res.render('check', {
width750: true,
localCss: true
});
};
exports.submit = (req, res) => {
let captchaCode = _.get(req.session, 'captcha');
let remoteIp = req.get('X-Forwarded-For') || req.ip;
if (remoteIp.indexOf(',') > 0) {
let arr = remoteIp.split(',');
remoteIp = arr[0];
}
if (req.body.captcha === captchaCode) {
let key = `pc:limiter:${remoteIp}`;
cache.delAsync(key).then(() => {
return res.json({
code: 200
});
}).catch(() => {
return res.json({
code: 400
});
});
} else {
return res.json({
code: 400
});
}
};
... ...
... ... @@ -9,9 +9,12 @@
const router = require('express').Router(); // eslint-disable-line
const cRoot = './controllers';
const ads = require(`${cRoot}/ads`);
const check = require(`${cRoot}/check`);
// routers
router.get('/ads', ads.index);
router.get('/check', check.index);
router.post('/check/submit', check.submit);
module.exports = router;
... ...
<div class="check-page">
<div class="title">请输入正确的验证码,继续访问</div>
<div id="js-img-check"></div>
<div class="submit">
确认
</div>
</div>
... ...
... ... @@ -233,7 +233,7 @@ exports.index = (req, res, next) => {
value.cn_alphabet = productNameProcess(value.cn_alphabet);
}
value.url = helpers.urlFormat(`/product/pro_${value.product_id}_${value.goodsId}/${value.cn_alphabet}.html`) + `?openby:yohobuy={"action":"go.productDetail","params":{"product_skn":${value.product_skn}}}`;
value.url = helpers.urlFormat(`/product/${value.product_skn}.html`) + `?openby:yohobuy={"action":"go.productDetail","params":{"product_skn":${value.product_skn}}}`; // 商品url改版
return value;
});
... ... @@ -431,7 +431,7 @@ exports.verifystudent = (req, res, next) => {
value.cn_alphabet = productNameProcess(value.cn_alphabet);
}
value.url = helpers.urlFormat(`/product/pro_${value.product_id}_${value.goodsId}/${value.cn_alphabet}.html`) + `?openby:yohobuy={"action":"go.productDetail","params":{"product_skn":${value.product_skn}}}`;
value.url = helpers.urlFormat(`/product/${value.product_skn}.html`) + `?openby:yohobuy={"action":"go.productDetail","params":{"product_skn":${value.product_skn}}}`; // 商品url改版
return value;
});
return getUser(uid).then((user) => {
... ...
... ... @@ -123,7 +123,7 @@ const _schoolTotal = () => {
// 资源位
const _resource = () => {
return service.get('/operations/api/v5/resource/get', {
content_code: '2daa99e69c27aba77ed3884814b78014',
content_code: '1cff7f47ca7057ef6ac00cbf2efc37ad',
});
};
... ... @@ -221,42 +221,42 @@ const index = (params) => {
resu.picList = {
bannerPic: helpers.image(pList[0].src, 750, 701),
title1: helpers.image(pList[1].src, 750, 114),
title2: helpers.image(pList[2].src, 750, 114),
title3: helpers.image(pList[3].src, 750, 114),
title4: helpers.image(pList[4].src, 750, 114),
pri1: helpers.image(pList[5].src, 345, 154),
pri2: helpers.image(pList[6].src, 345, 154),
pri3: helpers.image(pList[7].src, 345, 154),
pri4: helpers.image(pList[8].src, 345, 154),
title1: helpers.image(pList[9].src, 750, 114),
title2: helpers.image(pList[12].src, 750, 114),
title3: helpers.image(pList[14].src, 750, 114),
title4: helpers.image(pList[15].src, 750, 114),
pri1: helpers.image(pList[1].src, 345, 154),
pri2: helpers.image(pList[3].src, 345, 154),
pri3: helpers.image(pList[5].src, 345, 154),
pri4: helpers.image(pList[7].src, 345, 154),
act1: {
src: helpers.image(pList[9].src, 375, 444),
url: pList[9].url
},
act2: {
src: helpers.image(pList[10].src, 375, 444),
url: pList[10].url
},
invite: helpers.image(pList[11].src, 750, 444),
act2: {
src: helpers.image(pList[11].src, 375, 444),
url: pList[11].url
},
invite: helpers.image(pList[16].src, 750, 444),
dia1: {
src: helpers.image(pList[12].src, 560, 567),
url: pList[12].url
src: helpers.image(pList[2].src, 560, 567),
url: pList[2].url
},
dia2: {
src: helpers.image(pList[13].src, 560, 567),
url: pList[13].url
src: helpers.image(pList[4].src, 560, 567),
url: pList[4].url
},
dia3: {
src: helpers.image(pList[14].src, 560, 697),
url: pList[14].url
src: helpers.image(pList[6].src, 560, 697),
url: pList[6].url
},
dia4: {
src: helpers.image(pList[15].src, 560, 488),
url: pList[15].url
src: helpers.image(pList[8].src, 560, 488),
url: pList[8].url
},
dia5: {
src: helpers.image(pList[16].src, 560, 416),
url: pList[16].url
src: helpers.image(pList[13].src, 560, 416),
url: pList[13].url
},
};
}
... ...
... ... @@ -146,7 +146,7 @@ const _formatOrderGoods = (orderGoods, count, haveLink, tickets) => {
/* 商品链接 */
if (haveLink && value.product_skn) {
Object.assign(goods, {
link: helpers.urlFormat('/product/show_' + value.product_skn + '.html')
link: helpers.urlFormat('/product/' + value.product_skn + '.html') // 商品url改版
});
}
... ...
... ... @@ -42,7 +42,7 @@ const getProductData = (params) => {
return '';
} else {
_.forEach(result.data, (item) => {
item.url = helpers.urlFormat(`/product/pro_${item.productId}_${item.goodsId}/${item.cnAlphabet}.html`); // eslint-disable-line
item.url = helpers.urlFormat(`/product/${item.productSkn}.html`); // 商品url改版 // eslint-disable-line
item.url = helpers.appUrlFormat(item.url, 'go.productDetail', {
product_skn: item.productSkn
});
... ...
... ... @@ -6,6 +6,7 @@
'use strict';
const helpers = global.yoho.helpers;
const _ = require('lodash');
const headerModel = require('../../../doraemon/models/header'); // 头部model
const indexModel = require('../models/index');
... ... @@ -153,6 +154,11 @@ const add = (req, res, next) => {
// uid = 20422448;
return indexModel.addToCart(productSku, buyNumber, goodsType, isEdit, promotionId, uid, shoppingKey).then(data => {
if (!shoppingKey && _.has(data, 'data.shopping_key')) {
res.cookie('_SPK', data.data.shopping_key, {
expires: new Date(Date.now() + 86400 * 360)
});
}
data ? res.json(data) : res.status(400).json({
message: '操作失败'
});
... ...
... ... @@ -181,6 +181,7 @@ exports.orderSub = (req, res, next) => {
let yohoCoin = req.body.yohoCoin || 0;
let skuList = req.body.skuList || '';
let orderInfo;
let isWechat = req.yoho.isWechat;
try {
orderInfo = JSON.parse(req.cookies['order-info']);
... ... @@ -260,11 +261,11 @@ exports.orderSub = (req, res, next) => {
result = yield cartModel.orderSub(uid, addressId, 'bundle', deliveryTimeId,
deliveryId, invoices, paymentTypeId, paymentType, msg, couponCode,
yohoCoin, null, unionKey, userAgent, times, activityInfo, ip);
yohoCoin, null, unionKey, userAgent, times, activityInfo, ip, isWechat);
} else {
result = yield cartModel.orderSub(uid, addressId, cartType, deliveryTimeId,
deliveryId, invoices, paymentTypeId, paymentType, msg, couponCode,
yohoCoin, skuList, unionKey, userAgent, null, null, ip);
yohoCoin, skuList, unionKey, userAgent, null, null, ip, isWechat);
}
// 提交成功清除Cookie
... ...
... ... @@ -61,7 +61,7 @@ exports.ensure = (req, res, next) => {
page: 'seckill',
pageHeader: headerModel.setNav({
navTitle: '确认订单',
backUrl: '/product/show_' + skn + '.html'
backUrl: '/product/' + skn + '.html' // 商品url改版
}),
}, view));
}
... ... @@ -106,7 +106,7 @@ exports.ensure = (req, res, next) => {
page: 'seckill',
pageHeader: headerModel.setNav({
navTitle: '确认订单',
backUrl: '/product/show_' + skn + '.html'
backUrl: '/product/' + skn + '.html' // 商品url改版
}),
cartToken: crypto.encryption(SLAT, [sku, activityId].join(''))
}, view));
... ...
... ... @@ -2,7 +2,7 @@
* @Author: Targaryen
* @Date: 2017-01-03 17:42:41
* @Last Modified by: Targaryen
* @Last Modified time: 2017-02-27 16:34:09
* @Last Modified time: 2017-03-01 16:38:39
*/
'use strict';
... ... @@ -148,7 +148,8 @@ const Wechat = {
*/
getOpenid(code, originalUrl) {
if (!code) {
let baseUrl = 'http://m.yohobuy.com' + originalUrl;
let isProduction = process.env.NODE_ENV === 'production';
let baseUrl = (isProduction ? 'https://m.yohobuy.com' : 'http://m.yohobuy.com') + originalUrl;
let redirectUrl = tools.createOauthUrlForCode(baseUrl);
logger.info('payCenter: wechat pay no code');
... ... @@ -178,7 +179,7 @@ const Wechat = {
let resParams = {
appId: unifiedOrderResult.appid,
timeStamp: parseInt(Date.parse(new Date()) / 1000, 10),
timeStamp: parseInt(Date.parse(new Date()) / 1000, 10) + '',
nonceStr: nonceStr,
package: 'prepay_id=' + unifiedOrderResult.prepay_id,
signType: 'MD5',
... ...
... ... @@ -178,12 +178,13 @@ exports.ticketsOrderCompute = (uid, productSku, buyNumber, yohoCoin) => {
* @param string|null $userAgent 联盟过来用户下单时需要的User-Agent信息
* @param int $times
* @param null $activityInfo 套餐数据
* @param isWechat 是否是微信商城
* @return array 接口返回的数据
*/
exports.orderSub = (uid, addressId, cartType, deliveryTime,
deliveryWay, invoices, paymentId, paymentType, remark,
couponCode, yohoCoin, skuList, qhyUnio,
userAgent, times, activityInfo, ip) => {
userAgent, times, activityInfo, ip, isWechat) => {
if (!qhyUnio) {
qhyUnio = '';
}
... ... @@ -215,7 +216,7 @@ exports.orderSub = (uid, addressId, cartType, deliveryTime,
return shoppingAPI.orderSub(uid, addressId, cartType, deliveryTime,
deliveryWay, invoices, paymentId, paymentType,
remark, couponCode, yohoCoin, skuList, qhyUnio,
userAgent, times, activityInfo, ip).then(orderSubRes => {
userAgent, times, activityInfo, ip, isWechat).then(orderSubRes => {
let finalResult = {};
if (orderSubRes && orderSubRes.data && orderSubRes.data.is_hint === 'Y') {
... ...
... ... @@ -57,7 +57,7 @@ let indexRedirect = (req, res) => {
if (param) {
param = '?' + param;
}
res.redirect(`/${req.yoho.channel}-brands/${param}`);
res.redirect(301, `/${req.yoho.channel}-brands/${param}`);
};
let brandList = (req, res, next) => {
... ...
... ... @@ -13,6 +13,7 @@ const footerModel = require('../../../doraemon/models/footer_tab'); // 底部tab
const guangProcess = require(`${global.utils}/guang-process`);
const stringProcess = require(`${global.utils}/string-process`);
const Promise = require('bluebird');
const qs = require('querystring');
const channels = {
boys: 1,
girl: 2,
... ... @@ -87,8 +88,22 @@ const editor = (req, res, next) => {
// 301到新路由
const editorRedirect = (req, res, next) => {
if (req.query.id) {
res.redirect(`${req.query.id}`);
let id = req.query.id;
if (id) {
let redirectUrl = '/guang/author';
if (req.yoho.channel !== req.cookies._Channel) {
redirectUrl += `-${req.yoho.channel}`;
}
delete req.query.id;
let param = qs.stringify(req.query);
if (param) {
param = '?' + param;
}
redirectUrl += `-${id}/${param}`;
res.redirect(redirectUrl);
} else {
return next();
}
... ...
... ... @@ -13,6 +13,7 @@ const stringProcess = require(`${global.utils}/string-process`);
const guangProcess = require(`${global.utils}/guang-process`);
const productDetailModel = require('../../product/models/detail');
const headerModel = require('../../../doraemon/models/header'); // 头部model
const qs = require('querystring');
const channels = {
boys: 1,
girl: 2,
... ... @@ -362,102 +363,113 @@ const index = (req, res, next) => {
data.guang.channel = channel;
data.guang.isShare = isShare;
if (detail.code !== 400) {
if (!detail.getArticle) {
// TODO 跳转到逛首页
return;
}
if (isShare && detail && detail.sideNav) {
data.sideNav = detail.sideNav;
}
// 作者信息数据
if (detail && detail.getAuthor && (typeof detail.getAuthor.name !== 'undefined')) {
data.guang.author = {
avatar: detail.getAuthor.avatar.replace('http://', '//'),
name: detail.getAuthor.name,
intro: detail.getAuthor.author_desc
};
// guang双头部的问题 20160601
// 正确的URL
let url = `${detail.getAuthor.url}&openby:yohobuy={"action":"go.h5","params":{"param":{},"share":"","id":${detail.getAuthor.author_id},"type":0,"islogin":"N","url":"${detail.getAuthor.url}"}}`; // eslint-disable-line
if (detail.code === 400) {
return next();
}
if (!detail.getArticle) {
// TODO 跳转到逛首页
return;
}
data.guang.author.url = helpers.https(url);
}
let guang = data.guang;
if (isShare && detail && detail.sideNav) {
data.sideNav = detail.sideNav;
}
guang.detail = {
id: _.get(detail, 'getArticle.id'),
title: detail.getArticle.article_title,
publishTime: detail.getArticle.publishTime,
pageView: detail.getArticle.pageViews,
content: []
// 作者信息数据
if (detail && detail.getAuthor && (typeof detail.getAuthor.name !== 'undefined')) {
data.guang.author = {
avatar: detail.getAuthor.avatar.replace('http://', '//'),
name: detail.getAuthor.name,
intro: detail.getAuthor.author_desc
};
// guang双头部的问题 20160601
// 正确的URL
let url = `${detail.getAuthor.url}&openby:yohobuy={"action":"go.h5","params":{"param":{},"share":"","id":${detail.getAuthor.author_id},"type":0,"islogin":"N","url":"${detail.getAuthor.url}"}}`; // eslint-disable-line
if (detail.getArticleContent) {
// 生成内容部分
return _pageArticleContent(detail.getArticleContent,
isApp,
gender,
isWeixin,
isqq,
isWeibo).then((contents) => {
guang.detail.content = contents;
// 相关品牌
if (detail.getBrand && detail.getBrand.length) {
guang.relatedBrand = _relatedBrand(detail.getBrand);
}
data.guang.author.url = helpers.https(url);
}
let guang = data.guang;
guang.detail = {
id: _.get(detail, 'getArticle.id'),
title: detail.getArticle.article_title,
publishTime: detail.getArticle.publishTime,
pageView: detail.getArticle.pageViews,
content: []
};
if (!detail.getArticleContent) {
return next();
}
// 相关标签
if (detail.getArticle.tags && detail.getArticle.tags.length) {
guang.relatedTag = _relatedTag(detail.getArticle.tags, isApp);
}
// 生成内容部分
return _pageArticleContent(detail.getArticleContent,
isApp,
gender,
isWeixin,
isqq,
isWeibo).then((contents) => {
guang.detail.content = contents;
// 相关品牌
if (detail.getBrand && detail.getBrand.length) {
guang.relatedBrand = _relatedBrand(detail.getBrand);
}
// 相关文章
if (detail.getOtherArticle && detail.getOtherArticle.length) {
guang.relatedInfo = _relatedInfo(detail.getOtherArticle, isApp);
}
// 相关标签
if (detail.getArticle.tags && detail.getArticle.tags.length) {
guang.relatedTag = _relatedTag(detail.getArticle.tags, isApp);
}
// 分享参数
if (detail.getArticle.cover_image) {
let shareInfo = _shareInfo(id, detail.getArticle);
// 相关文章
if (detail.getOtherArticle && detail.getOtherArticle.length) {
guang.relatedInfo = _relatedInfo(detail.getOtherArticle, isApp);
}
Object.assign(guang, shareInfo);
data.title = detail.getArticle.article_title + ' | Yoho!Buy有货 | 潮流购物逛不停';
data.title_more = true;
data.description = detail.getArticle.article_summary;
data.description_more = true;
}
// 分享参数
if (detail.getArticle.cover_image) {
let shareInfo = _shareInfo(id, detail.getArticle);
// 标识有微信分享
data.hasWxShare = true;
res.render('info/index', Object.assign({
page: 'info-index',
title: '逛',
gender: gender,
wechatShare: true,
isWeixin: isWeixin,
localCss: true,
isShare: isShare
}, data, parameter));
});
} else {
next();
return;
}
Object.assign(guang, shareInfo);
data.title = detail.getArticle.article_title + ' | Yoho!Buy有货 | 潮流购物逛不停';
data.title_more = true;
data.description = detail.getArticle.article_summary;
data.description_more = true;
}
}
// 标识有微信分享
data.hasWxShare = true;
res.render('info/index', Object.assign({
page: 'info-index',
title: '逛',
gender: gender,
wechatShare: true,
isWeixin: isWeixin,
localCss: true,
isShare: isShare
}, data, parameter));
}).catch(next);
}).catch(next);
};
// 301到新路由
const indexRedirect = (req, res, next) => {
if (req.query.id) {
res.redirect(`${req.query.id}`);
let id = req.query.id;
if (id) {
let redirectUrl = '/guang/info/';
if (req.yoho.channel !== req.cookies._Channel) {
redirectUrl += `${req.yoho.channel}-`;
}
delete req.query.id;
let param = qs.stringify(req.query);
if (param) {
param = '?' + param;
}
redirectUrl += `${id}.html${param}`;
res.redirect(redirectUrl);
} else {
return next();
}
... ...
... ... @@ -95,7 +95,7 @@ exports.indexRedirect = (req, res) => {
if (param) {
param = '?' + param;
}
res.redirect(`/guang/${req.yoho.channel}-plusstar/${param}`);
res.redirect(301, `/guang/${req.yoho.channel}-plusstar/${param}`);
};
exports.userSkn = (req, res, next) => {
... ...
... ... @@ -185,8 +185,7 @@ const getNewProduct = (brandId, gender, url, isApp) => {
list.cn_alphabet = productNameProcess(list.cn_alphabet);
}
let productUrl = '//m.yohobuy.com/product/pro_' + list.product_id + '_' +
list.goods_list[0].goods_id + '/' + list.cn_alphabet + '.html';
let productUrl = '//m.yohobuy.com/product/' + list.product_skn + '.html'; // 商品url改版
if (isApp) {
productUrl += `?openby:yohobuy={"action":"go.productDetail","params":{"product_skn":"${list.product_skn}"}}`;
... ...
... ... @@ -42,7 +42,7 @@ router.post('/plusstar/resources-goodsList', plusstar.resourcesGoodsList); //
router.get('/', index.index); // 逛首页
router.get('/tags/index', index.tag); // 逛标签页
router.get('/author/index', index.editor); // 编辑简介
router.get('/author/index', rewrite.channel, index.editorRedirect); // 编辑简介
router.get(/^\/author-([^\/]+)/, rewrite.resolve, index.editor); // 编辑简介 SEO优化
router.get('/index/page', index.pageData); // 逛列表页面的资讯分页
... ... @@ -51,8 +51,9 @@ router.post('/opt/praiseArticle', opt.praiseArticle); // 资讯文章点赞 (H5
router.post('/opt/collectArticle', opt.collectArticle); // 资讯文章收藏 (H5里显示收藏)
router.post('/opt/favoriteBrand', opt.favoriteBrand); // 品牌收藏
router.get('/info/index', info.index); // 逛详情页
// router.get(/^\/info\/(.*?-\d+)/, rewrite.resolve, info.index); // 逛详情页 SEO优化
router.get('/info/index', rewrite.channel, info.indexRedirect); // 逛详情页
router.get(/^\/info\/(.*?)\.html/, rewrite.resolve, info.index); // 逛详情页 SEO优化
router.get('/:id.html', info.index); // 逛详情页(兼容 PC 跳转过来的链接)
router.get('/info/mini', info.mini); // 逛mini内容页
router.get('/info/foryoho', info.foryoho); // 逛foryoho内容页
... ...
... ... @@ -53,9 +53,7 @@ const favProduct = (uid, page, limit) => {
if (val.goodsId && val.cnAlphabet) {
obj = _.assign(obj, {
link: config.siteUrl + '/product/pro_' +
val.productId + '_' + val.goodsId + '/' +
val.cnAlphabet + '.html'
link: config.siteUrl + '/product/' + val.productSkn + '.html' // 商品url改版
});
} else {
obj = _.assign(obj, {
... ... @@ -177,8 +175,7 @@ const favfavBrand = (uid, page, limit) => {
_.forEach(val.newProduct, function(data, key) {
obj.productList.push({
link: '/product/pro_' + data.productId + '_' +
data.goods[0].id + '/' + data.cnAlphabet + '.html',
link: '/product/' + data.productSkn + '.html', // 商品url改版
imgUrl: data.defaultImages,
price: '¥' + Number(data.marketPrice).toFixed(2),
discount: data.marketPrice > data.salesPrice ? '¥' + Number(data.salesPrice).toFixed(2) : false,
... ...
... ... @@ -258,7 +258,7 @@ const recordContent = (uid, udid, page, limit) => {
product_skn: val.product_skn,
storage: val.storage,
image: val.image,
link: '/product/show_' + val.product_skn + '.html',
link: '/product/' + val.product_skn + '.html', // 商品url改版
sales_price: val.sales_price,
market_price: (val.market_price - val.sales_price) > 0 ? val.market_price : false,
invalidGoods: val.status === 0
... ...
... ... @@ -51,7 +51,7 @@ const _formatOrderGoods = (orderGoods, count, haveLink, tickets) => {
/* 商品链接 */
if (haveLink && value.product_skn) {
Object.assign(goods, {
link: helpers.urlFormat('/product/show_' + value.product_skn + '.html')
link: helpers.urlFormat('/product/' + value.product_skn + '.html') // 商品url改版
});
}
... ...
... ... @@ -239,7 +239,7 @@ const orderDetailData = (uid, orderCode) => {
if (data.productSkn) {
obj = _.assign(obj, {
link: '/product/show_' + data.productSkn + '.html'
link: '/product/' + data.productSkn + '.html' // 商品url改版
});
}
... ...
... ... @@ -111,7 +111,9 @@ const local = {
res.render('login', {
width750: true,
loginIndex: true, // 模板中使用JS的标识
captchaShow: _.get(req.session, 'login.errorCount') <= 0,
// captchaShow: _.get(req.session, 'login.errorCount') <= 0,
captchaShow: true, // 170306 因为暴力破解密码问题,要求每次都展示验证码
// 返回的URL链接
backUrl: 'javascript:history.go(-1)', // eslint-disable-line
... ... @@ -162,7 +164,9 @@ const local = {
// 返回的URL链接
backUrl: 'javascript:history.go(-1)', // eslint-disable-line
loginInternational: true, // 模板中使用JS的标识
captchaShow: _.get(req.session, 'login.errorCount') <= 0,
// captchaShow: _.get(req.session, 'login.errorCount') <= 0,
captchaShow: true, // 170306 因为暴力破解密码问题,要求每次都展示验证码
isPassportPage: true, // 模板中模块标识
headerText: '登录',
areaCode: '+86', // 默认区号
... ... @@ -173,6 +177,10 @@ const local = {
});
},
login: (req, res, next) => {
// 170306 因为暴力破解密码问题,要求每次都校验验证码
_.set(req.session, 'login.errorCount', 0);
let count = _.get(req.session, 'login.errorCount');
if (count == null) { // eslint-disable-line
... ...
... ... @@ -8,6 +8,7 @@ const detailModel = require('../models/detail');
const newDetailModel = require('../models/new-detail');
const listModel = require('../models/list');
const headerModel = require('../../../doraemon/models/header'); // 头部model
const qs = require('querystring');
const helpers = global.yoho.helpers;
const newDetail = {
... ... @@ -16,7 +17,9 @@ const newDetail = {
let goodsId;
let productSkn;
if (req.params[0] && req.params[1]) {
if (req.query.id) {
id = req.query.id;
} else if (req.params[0] && req.params[1]) {
id = req.params[0];
goodsId = req.params[1];
} else if (req.params[0]) {
... ... @@ -59,6 +62,37 @@ const newDetail = {
}).catch(next);
},
// 301到新路由
indexRedirect(req, res, next) {
let param = qs.stringify(req.query);
if (param) {
param = '?' + param;
}
return new Promise((resolve, reject) => {
if (req.params[0] && req.params[1]) {
newDetailModel.getProductData({
id: req.params[0],
ua: req.get('user-agent') || ''
}).then(result => {
if (_.isEmpty(result)) {
return reject();
}
resolve(result.productSkn);
}).catch(next);
} else if (req.params[0]) {
resolve(req.params[0]);
} else {
reject();
}
}).then(skn => {
return res.redirect(`/product/${skn}.html${param}`);
}, () => {
return next();
});
},
/*
* 商品基本信息 SKN 进入 pagecache重构
... ...
... ... @@ -86,7 +86,7 @@ const newGoodsRedirect = (req, res) => {
if (param) {
param = '?' + param;
}
res.redirect(`/product/${req.yoho.channel}-new/${param}`);
res.redirect(301, `/product/${req.yoho.channel}-new/${param}`);
};
/**
... ...
... ... @@ -106,7 +106,7 @@ let indexRedirect = (req, res) => {
if (param) {
param = '?' + param;
}
res.redirect(`/product/${req.yoho.channel}-sale/${param}`);
res.redirect(301, `/product/${req.yoho.channel}-sale/${param}`);
};
/**
... ...
... ... @@ -596,7 +596,7 @@ let _detailDataPkgAsync = (origin, uid, vipLevel, ua) => {
// 用户未登录时
if (!uid) {
dest.loginUrl = helpers.urlFormat('/signin.html', {
refer: helpers.urlFormat('/product/show_' + origin.product_skn + '.html')
refer: helpers.urlFormat('/product/' + origin.product_skn + '.html') // 商品url改版
});
}
... ...
... ... @@ -104,8 +104,7 @@ const selectHotrank = (yhChannel, gender, sort, tabId, limit, page, notab) => {
}
one = _.assign(one, {
url: '/product/pro_' + data.product_id + '_' + data.goods_list[0].goods_id +
'/' + data.cn_alphabet + '.html',
url: '/product/' + data.product_skn + '.html', // 商品url改版
thumb: data.default_images,
rank: limit * (page - 1) + index + 1,
name: data.product_name,
... ...
... ... @@ -8,6 +8,7 @@
'use strict';
const $ = require('cheerio');
const api = global.yoho.API;
const helpers = global.yoho.helpers;
const yhchannelMap = {
boys: '1',
... ... @@ -28,7 +29,13 @@ module.exports = (data) => {
let goodThumb = goodsContainer.find('.good-thumb');
goodThumb.each(function(index, domEle) {
$(domEle).attr('href', $(domEle).attr('href').split('?')[0]);
let href = $(domEle).attr('href').split('?')[0];
let skn = $(domEle).closest('.good-info').data('id');
if (skn) {
href = helpers.urlFormat(`/product/${skn}.html`); // 商品url改版
}
$(domEle).attr('href', href);
});
result = goodsContainer.append(
... ...
... ... @@ -34,7 +34,7 @@ const getPreferenceData = (data) => {
product_name: value.product_name,
default_images: value.default_images,
is_soon_sold_out: value.is_soon_sold_out === 'Y',
url: helpers.urlFormat(`/product/pro_${value.product_id}_${value.goodsId}/${value.cn_alphabet}.html`),
url: helpers.urlFormat(`/product/${value.product_skn}.html`), // 商品url改版
market_price: value.market_price,
sales_price: value.sales_price
};
... ...
... ... @@ -160,7 +160,7 @@ const _getLimitCodeUrl = (productCode, skn, ua) => {
// if (!uid) {
// let params = {};
// params.refer = helpers.urlFormat('/product/show_' + origin.erpProductId + '.html');
// params.refer = helpers.urlFormat('/product/' + origin.erpProductId + '.html');
// dest.loginUrl = helpers.urlFormat('/signin.html', params);
// }
... ... @@ -579,7 +579,7 @@ const _getLimitCodeUrl = (productCode, skn, ua) => {
// // 用户未登录时
// if (!uid) {
// dest.loginUrl = helpers.urlFormat('/signin.html', {
// refer: helpers.urlFormat('/product/show_' + origin.productSkn + '.html')
// refer: helpers.urlFormat('/product/' + origin.productSkn + '.html')
// });
// }
... ... @@ -1151,7 +1151,7 @@ const _detailDataPkg = (origin, ua) => {
// 用户未登录时 pagecache重构
// if (!uid) {
// dest.loginUrl = helpers.urlFormat('/signin.html', {
// refer: helpers.urlFormat('/product/show_' + origin.product_skn + '.html')
// refer: helpers.urlFormat('/product/' + origin.product_skn + '.html')
// });
// }
... ... @@ -1539,7 +1539,7 @@ let _detailDataPkgAsync = (origin, uid, vipLevel, ua) => {
// 用户未登录时
if (!uid) {
dest.loginUrl = helpers.urlFormat('/signin.html', {
refer: helpers.urlFormat('/product/show_' + origin.product_skn + '.html')
refer: helpers.urlFormat('/product/' + origin.product_skn + '.html') // 商品url改版
});
}
... ...
... ... @@ -60,10 +60,10 @@ const bundle = require(`${cRoot}/bundle`);
// 因为正则匹配原因,秒杀详情页路由要放在普通详情页前面,待解决
router.get(/^\/seckill\/show_([\d]+)/, seckillDetail.indexSkn); // 秒杀商品详情页 SKN 进入
router.get(/^\/seckill\/pro_([\d]+)_([\d]+)/, seckillDetail.index); // 秒杀商品详情页进入
router.get(/^\/pro_([\d]+)_([\d]+)/, newDetail.index); // 商品详情页
router.get(/^\/pro_([\d]+)_([\d]+)/, newDetail.indexRedirect); // 商品详情页
// /show_51047967.html
router.get(/^\/show_([\d]+)/, newDetail.index); // 商品详情页 SKN 进入
// router.get(/^\/p([\d]+)\.html/, newDetail.index); // 商品详情页 SKN 进入 SEO优化
router.get(/^\/show_([\d]+)/, newDetail.indexRedirect); // 商品详情页 SKN 进入
router.get(/^\/(\d+)\.html/, newDetail.index); // 商品详情页 SKN 进入 SEO优化
router.get('/detail/sknData.json', newDetail.sknData); // 商品咨询,评价,店铺
router.get('/detail/intro/:productskn', detail.intro); // 商品内嵌页
... ...
... ... @@ -153,11 +153,12 @@ exports.checkTickets = (uid, productSku, buyNumber, useYohoCoin, yohoCoinMode) =
* @param string|null $userAgent 联盟过来用户下单时需要的User-Agent信息
* @param $times
* @param null $activityInfo 套餐信息
* @param isWechat 是否是微信商城
* @return array 接口返回的数据
*/
exports.orderSub = (uid, addressId, cartType, deliveryTime,
deliveryWay, invoices, paymentId, paymentType, remark, couponCode,
yohoCoin, skuList, qhyUnion, userAgent, times, activityInfo, ip) => {
yohoCoin, skuList, qhyUnion, userAgent, times, activityInfo, ip, isWechat) => {
if (!activityInfo) {
activityInfo = null;
}
... ... @@ -226,6 +227,11 @@ exports.orderSub = (uid, addressId, cartType, deliveryTime,
params.qhy_union = qhyUnion;
}
// 是否是微信商城
if (isWechat) {
params.client_type = 'wechat';
}
return api.post('', params, {
headers: {
'X-Forwarded-For': ip || '',
... ...
... ... @@ -206,4 +206,31 @@ exports.queryGlobalOrder = (req, res) => {
});
};
/**
* Request: 获取评价原因
* type: GET
* params:
* cvId 会话id
*/
exports.queryReasons = (req, res) => {
let uid = req.user.uid;
if (!uid) {
uid = req.body.uid;
}
const cvId = req.query.conversationId;
imApi.queryReasons(cvId)
.then(result=> {
res.json(result);
})
.catch(() => {
return res.json({
code: 500,
message: '拉取评价原因失败'
});
});
};
... ...
... ... @@ -133,3 +133,15 @@ exports.queryGlobalOrder = uid => {
return ImService.get('/api/order/queryGlobalOrder', params);
};
/**
* 获取评价原因
* @param cvId 会话ID
*/
exports.queryReasons = cvId => {
let params = {
conversationId: cvId
};
return ImService.get('/api/evalute/queryReasonByConversationId', params);
};
... ...
... ... @@ -24,6 +24,7 @@ router.get('/im/fetchHistory', chat.fetchHistory);
router.get('/getOrders', chat.getOrders);
router.get('/im/global-list', chat.queryGlobalOrder);
router.get('/im/order-list', chat.fetchOrders);
router.get('/im/queryReasons', chat.queryReasons);
router.post('/leavemsg/save.json', chat.saveMSG);
router.post('/im/saveEvalute', chat.saveEvalute);
... ...
... ... @@ -9,8 +9,15 @@
<i></i>
<i></i>
</div>
<div class="rank"> </div>
<textarea class="words-to-say" maxlength="50" placeholder="还想吐槽下(选填)"></textarea>
<div class="rank"></div>
<div class="more-comment">
<div class="cause">
{{#each causeList}}
<span>{{value}}</span>
{{/each}}
</div>
<textarea class="words-to-say" maxlength="50" placeholder="还想吐槽下(选填)"></textarea>
</div>
<button class="submit">提交</button>
</div>
</div>
\ No newline at end of file
... ...
... ... @@ -15,14 +15,15 @@ const domains = {
// liveApi: 'http://testapi.live.yohops.com:9999/',
// singleApi: 'http://api-test3.yohops.com:9999/',
api: 'http://dev-api.yohops.com:9999/',
service: 'http://dev-service.yohops.com:9999/',
liveApi: 'http://api.live.yoho.cn/',
singleApi: 'http://single.yoho.cn/',
imSocket: 'wss://imsocket.yohobuy.com:443',
imCs: 'https://imhttp.yohobuy.com/api',
imServer: 'https://imhttp.yohobuy.com/server'
imSocket: 'ws://socket.yohobuy.com:10240',
imCs: 'https://im.yohobuy.com/api',
imServer: 'https://im.yohobuy.com/server'
};
module.exports = {
... ... @@ -72,7 +73,6 @@ module.exports = {
udp: { // send by udp
measurement: 'yohobuy_wap_node_log',
level: 'error', // logger level
host: 'influxdblog.web.yohoops.org', // influxdb host
port: '4444' // influxdb port
},
console: {
... ... @@ -107,7 +107,8 @@ module.exports = {
key: '7e6f3307b64cc87c79c472814b88f7fb',
appSecret: 'ce21ae4a3f93852279175a167e54509b',
notifyUrl: domains.service + 'payment/weixin_notify',
}
},
maxQps: 1200
};
if (isProduction) {
... ...
'use strict';
const limiter = require('../middleware/limiter/index');
module.exports = (req, res, next) => {
return limiter(req, res, next);
};
... ...
'use strict';
const _ = require('lodash');
const logger = global.yoho.logger;
const ip = require('./rules/ip-list');
const userAgent = require('./rules/useragent');
const qpsLimiter = require('./rules/qps-limit');
const fakerLimiter = require('./rules/faker-limit');
const captchaPolicy = require('./policies/captcha');
const reporterPolicy = require('./policies/reporter');
const IP_WHITE_LIST = [
// '106.38.38.146',
// '218.94.75.58'
];
const limiter = (rule, policy, context) => {
return rule(context, policy);
};
module.exports = (req, res, next) => {
let remoteIp = req.get('X-Forwarded-For') || req.connection.remoteAddress;
logger.debug('request remote ip: ', remoteIp);
if (remoteIp.indexOf(',') > 0) {
let arr = remoteIp.split(',');
remoteIp = arr[0];
}
const excluded = _.includes(IP_WHITE_LIST, remoteIp);
const enabled = !_.get(req.app.locals, 'wap.sys.noLimiter');
// 判断获取remoteIp成功,并且开关未关闭
if (enabled && remoteIp && !excluded) {
const context = {
req: req,
res: res,
next: next,
remoteIp: remoteIp
};
Promise.all([
limiter(userAgent, captchaPolicy, context),
limiter(ip, captchaPolicy, context),
limiter(qpsLimiter, captchaPolicy, context),
//limiter(fakerLimiter, reporterPolicy, context)
]).then((results) => {
let allPass = true, exclusion = false, policy = null;
logger.debug('limiter result: ' + JSON.stringify(results));
_.forEach(results, (result) => {
if (typeof result === 'object' && !exclusion) {
exclusion = result.exclusion;
}
if (!excluded && typeof result === 'function') {
allPass = false;
}
if (typeof result === 'function') {
policy = result;
}
});
if (exclusion) {
return next();
} else if (!allPass && policy) {
policy(req, res, next);
} else {
return next();
}
}).catch((err) => {
logger.error(err);
return next();
});
} else {
return next();
}
};
... ...
'use strict';
const helpers = global.yoho.helpers;
const _ = require('lodash');
const WHITE_LIST = [
'/3party/check',
'/passport/imagesNode',
'/passport/cert/headerTip',
'/passport/captcha/get',
'/3party/check/submit'
];
module.exports = (req, res, next) => {
let refer = req.method === 'GET' ? req.get('Referer') : '';
let limitAPI = helpers.urlFormat('/3party/check', {refer: refer});
let limitPage = helpers.urlFormat('/3party/check', {refer: req.protocol + '://' + req.get('host') + req.originalUrl});
if (_.indexOf(WHITE_LIST, req.path) >= 0) {
return next();
}
if (req.xhr) {
return res.json({
code: 400,
data: {refer: limitAPI}
});
}
return res.redirect(limitPage);
};
... ...
'use strict';
module.exports = (req, res, next) => {
return next();
};
... ...
'use strict';
const logger = global.yoho.logger;
const cache = global.yoho.cache.master;
const ONE_DAY = 60 * 60 * 24;
module.exports = (limiter, policy) => {
const req = limiter.req,
res = limiter.res,
next = limiter.next;
const key = `pc:limiter:faker:${limiter.remoteIp}`;
if (req.header('X-Requested-With') === 'XMLHttpRequest') {
cache.decrAsync(key, 1);
}
res.on('render', function() {
cache.incrAsync(key, 1);
});
return cache.getAsync(key).then((result) => {
if (result) {
if (result > 100) {
return Promise.resolve(policy);//policy(req, res, next);
} else {
return Promise.resolve(true);
}
} else {
cache.setAsync(key, 1, ONE_DAY); // 设置key,1m失效
return Promise.resolve(true);
}
});
};
... ...
'use strict';
const cache = global.yoho.cache.master;
const _ = require('lodash');
module.exports = (limiter) => {
const key = `pc:limiter:${limiter.remoteIp}`;
return cache.getAsync(key).then((result) => {
if (result && _.isNumber(result)) {
return Promise.resolve({
exclusion: result === -1
});
} else {
return Promise.resolve(true);
}
});
};
... ...
'use strict';
const logger = global.yoho.logger;
const cache = global.yoho.cache.master;
const config = global.yoho.config;
const ONE_DAY = 60 * 60 * 24;
const MAX_QPS = config.maxQps;
const _ = require('lodash');
const PAGES = {
'/product/\\/pro_([\\d]+)_([\\d]+)\\/(.*)/': 5,
'/product/list/index': 5
};
function urlJoin(a, b) {
if (_.endsWith(a, '/') && _.startsWith(b, '/')) {
return a + b.substring(1, b.length);
} else if (!_.endsWith(a, '/') && !_.startsWith(b, '/')) {
return a + '/' + b;
} else {
return a + b;
}
}
module.exports = (limiter, policy) => {
const req = limiter.req,
res = limiter.res,
next = limiter.next;
const key = `pc:limiter:${limiter.remoteIp}`;
res.on('render', function() {
let route = req.route ? req.route.path : '';
let appPath = req.app.mountpath;
if (_.isArray(route) && route.length > 0) {
route = route[0];
}
let pageKey = urlJoin(appPath, route.toString()); // route may be a regexp
let pageIncr = PAGES[pageKey] || 0;
if (/^\/p([\d]+)/.test(req.path)) {
pageIncr = 5;
}
if (pageIncr > 0) {
cache.incrAsync(key, pageIncr, (err) => {});
}
});
return cache.getAsync(key).then((result) => {
logger.debug('qps limiter: ' + key + '@' + result + ' max: ' + MAX_QPS);
if (result && _.isNumber(result)) {
if (result === -1) {
return Promise.resolve(true);
}
if (result > MAX_QPS) { // 判断 qps
cache.touch(key, ONE_DAY);
logger.debug('req limit', key);
return Promise.resolve(policy);
} else {
cache.incrAsync(key, 1); // qps + 1
return Promise.resolve(true);
}
} else {
cache.setAsync(key, 1, 60); // 设置key,1m失效
return Promise.resolve(true);
}
});
};
... ...
'use strict';
const cache = global.yoho.cache.master;
const _ = require('lodash');
const logger = global.yoho.logger;
module.exports = (limiter, policy) => {
const req = limiter.req,
res = limiter.res,
next = limiter.next;
const blackKey = 'pc:limiter:ua:black',
whiteKey = 'pc:limiter:ua:white';
const ua = limiter.req.header('User-Agent');
return Promise.all([
cache.getAsync(blackKey),
cache.getAsync(whiteKey)
]).then((args) => {
const blacklist = args[0] || [], whitelist = args[1] || [];
if (blacklist.length === 0 && whitelist.length === 0) {
return Promise.resolve(true);
}
const test = (list) => {
let result = false;
_.each(list, (item) => {
let regexp;
try {
regexp = new RegExp(item);
} catch (e) {
logger.error(e);
}
if (regexp.test(ua)) {
result = true;
}
});
return result;
};
if (test(blacklist)) {
return Promise.resolve(policy);
} else if (test(whitelist)) {
return Promise.resolve({
exclusion: true
});
} else {
return Promise.resolve(true);
}
});
};
... ...
... ... @@ -9,15 +9,19 @@ const typeLib = require('../../config/type-lib');
const _ = require('lodash');
const resolve = (req, res, next) => {
let path = req.params[0],
let path,
params = {
channel: req.yoho.channel
};
path = _.join(_.map(req.params, v => {
return v;
}), '-');
if (!path) {
return next();
}
let conditions = path.replace('.html', '').split('-');
let conditions = path.split('-').filter(cond => cond);
_.each(conditions, condition => {
if (typeLib.channels[condition]) {
... ... @@ -28,7 +32,7 @@ const resolve = (req, res, next) => {
if (item.length === 2) {
params[item[0]] = item[1];
}
} else if (condition >= 0) {
} else if (condition >= 0 && !params.id) {
params.id = _.parseInt(condition);
}
});
... ...
... ... @@ -6,7 +6,8 @@
<ul>
{{#list}}
<li class="hot-single-goods">
<a href="//m.yohobuy.com/product/show_{{product_skn}}">
<a href="//m.yohobuy.com/product/{{product_skn}}.html">
{{!--商品url改版 --}}
<img src="{{image2 default_images w=153 h=206 q=60}}" alt="goods" class="goods-pic">
<div class="goods-info">
<h3 class="price">&yen; {{sales_price}}</h3>
... ...
... ... @@ -7,7 +7,8 @@
<ul>
{{#list}}
<li class="new-user-good">
<a href="//m.yohobuy.com/product/show_{{product_skn}}">
<a href="//m.yohobuy.com/product/{{product_skn}}.html">
{{!--商品url改版 --}}
<img src="{{image default_images 128 171}}" alt="goods-pic" class="goods-pic" />
<div class="goods-info">
<h3 class="title">{{product_name}}</h3>
... ...
... ... @@ -7,7 +7,8 @@
<div class="vip-only-goods-list" {{#background}} style="background-image: url({{image src 640 330}})" {{/background}}>
<ul>
{{#list}}
<a href="//m.yohobuy.com/product/show_{{product_skn}}">
<a href="//m.yohobuy.com/product/{{product_skn}}.html">
{{!--商品url改版 --}}
<li class="vip-only-goods">
<img src="{{image default_images 153 206}}" alt="goods" class="goods-pic">
<div class="goods-info">
... ...
{
"name": "m-yohobuy-node",
"version": "5.4.21",
"version": "5.4.27",
"private": true,
"description": "A New Yohobuy Project With Express",
"repository": {
... ...
... ... @@ -6,7 +6,8 @@
<ul>
{{#list}}
<li class="hot-single-goods">
<a href="//m.yohobuy.com/product/show_{{product_skn}}">
<a href="//m.yohobuy.com/product/{{product_skn}}.html">
{{!--商品url改版 --}}
<img src="{{image2 default_images w=153 h=206 q=60}}" alt="goods" class="goods-pic">
<div class="goods-info">
<h3 class="price">&yen; {{sales_price}}</h3>
... ...
... ... @@ -7,7 +7,8 @@
<ul>
{{#list}}
<li class="new-user-good">
<a href="//m.yohobuy.com/product/show_{{product_skn}}">
<a href="//m.yohobuy.com/product/{{product_skn}}.html">
{{!--商品url改版 --}}
<img src="{{image default_images 128 171}}" alt="goods-pic" class="goods-pic" />
<div class="goods-info">
<h3 class="title">{{product_name}}</h3>
... ...
... ... @@ -7,7 +7,8 @@
<div class="vip-only-goods-list" {{#background}} style="background-image: url({{image src 640 400}})" {{/background}}>
<ul>
{{#list}}
<a href="//m.yohobuy.com/product/show_{{product_skn}}">
<a href="//m.yohobuy.com/product/{{product_skn}}.html">
{{!--商品url改版 --}}
<li class="vip-only-goods">
<img src="{{image default_images 153 206}}" alt="goods" class="goods-pic">
<div class="goods-info">
... ...
require('3party/check.page.css');
require('../common');
// 图片验证码
let ImgCheck = require('plugin/img-check');
let imgCheck = new ImgCheck('#js-img-check', {
useREM: {
rootFontSize: 40,
picWidth: 150
}
});
imgCheck.init();
$(function() {
$('.submit').on('click', function() {
$.ajax({
method: 'POST',
url: '/3party/check/submit',
data: {
captcha: $.trim(imgCheck.getResults())
},
success: function(ret) {
if (ret.code === 200) {
window.location.href = decodeURIComponent(window.queryString.refer) || '//m.yohobuy.com';
} else {
imgCheck.refresh();
}
}
});
});
});
... ...
... ... @@ -6,7 +6,7 @@ var phone,
newUserCouponPic = $('#newUserCouponPic').html(),
tipMessage = $('#tipMessage').html(),
activityID = $('#activityID').html(),
_weChatInterface = '//m.yohobuy.com/life/getSignPackage',
_weChatInterface = '//m.yohobuy.com/activity/wechat/share',
shareTitle = $('#shareTitle').val(),
shareImg = $('#shareImg').val(),
shareDesc = $('#shareDesc').val(),
... ... @@ -53,7 +53,7 @@ if (!$('#newUser').html()) {
* 微信分享
*/
if (typeof wx !== 'undefined') {
$.getJSON(_weChatInterface + '?pageurl=' +
$.getJSON(_weChatInterface + '?url=' +
encodeURIComponent(location.href.split('#')[0]) + '&callback=?',
function(json) {
var _appId, _timestamp, _nonceStr, _signature;
... ...
// 初始化config信息
var _weChatInterface = 'http://www.yohoboys.com/api/wechat/getSignPackage';// 签名等相关配置,yoho公众号
var _weChatInterface = '//m.yohobuy.com/activity/wechat/share';// 签名等相关配置,yoho公众号
$.getJSON(_weChatInterface + '?pageurl=' + encodeURIComponent(location.href.split('#')[0]) + '&callback=?', function(json) {
$.getJSON(_weChatInterface + '?url=' + encodeURIComponent(location.href.split('#')[0]) + '&callback=?', function(json) {
if (json !== undefined && json !== '') {
var _appId = json.appId.toString();
var _timestamp = json.timestamp;
... ...
... ... @@ -16,6 +16,14 @@ require('../common');
require('activity/promotion/promotion.page.css');
var share = require('../common/share');
share({
title: 'YOHO!BUY有货邀请同学认证赠好礼!立享【学生专属】4大特权!',
link: location.href,
desc: '每邀请1名同学完成认证立赠300有货币!上不封顶!',
imgUrl: 'http://img11.static.yhbimg.com/taobaocms/2017/01/17/16/0108d724a0ef1f001d3ee6010aa79d960e.png'
});
/*
* 筛选器
*/
... ... @@ -290,6 +298,18 @@ $(
}
}
if (($(".login-btn").length > 0) || $(".reg-now").length > 0) {
var shareUrl = location.href.replace('userUid=', 'oldUid=');
share({
title: 'YOHO!BUY有货邀请同学认证赠好礼!立享【学生专属】4大特权!',
link: shareUrl,
desc: '每邀请1名同学完成认证立赠300有货币!上不封顶!',
imgUrl: 'http://img11.static.yhbimg.com/taobaocms/2017/01/17/16/0108d724a0ef1f001d3ee6010aa79d960e.png'
});
}
$('.reg-now').on('click', function() {
checkStudent();
});
... ...
... ... @@ -6,7 +6,7 @@ var $ = require('yoho-jquery'),
dialog = require('../plugin/dialog'),
Hammer = require('yoho-hammer');
var _weChatInterface = '//m.yohobuy.com/life/getSignPackage',
var _weChatInterface = '//m.yohobuy.com/activity/wechat/share',
wx = window.wx,
C_ID,
getChannel;
... ... @@ -159,7 +159,7 @@ $('.on-lingqu', 'div.main-right-use').on('click', function() {
* 微信分享
*/
if (typeof wx !== 'undefined') {
$.getJSON(_weChatInterface + '?pageurl=' +
$.getJSON(_weChatInterface + '?url=' +
encodeURIComponent(location.href.split('#')[0]) + '&callback=?',
function(json) {
var _appId,
... ...
... ... @@ -6,7 +6,7 @@ var $ = require('yoho-jquery'),
dialog = require('../plugin/dialog'),
Hammer = require('yoho-hammer');
var _weChatInterface = '//m.yohobuy.com/life/getSignPackage',
var _weChatInterface = '//m.yohobuy.com/activity/wechat/share',
wx = window.wx,
C_ID,
getChannel;
... ... @@ -155,7 +155,7 @@ $('.on-lingqu', 'div.main-right-use').on('click', function() {
* 微信分享
*/
if (typeof wx !== 'undefined') {
$.getJSON(_weChatInterface + '?pageurl=' +
$.getJSON(_weChatInterface + '?url=' +
encodeURIComponent(location.href.split('#')[0]) + '&callback=?',
function(json) {
var _appId,
... ...
... ... @@ -20,9 +20,6 @@ var _ChannelVary = {
lifestyle: 4
};
// 尝试打开 APP
require('./common/open-app');
function cookie(name) {
var cookies = document.cookie,
cookieVal;
... ... @@ -222,12 +219,20 @@ $.extend({
$footer.removeClass('hide');
// 单击下载按钮 - 接受微信商城或者第三方来源的数据埋点信息
if (queryString().union_type) {
setCookie('unionTypeYas', queryString().union_type, {
let mktc = queryString().union_type || queryString().mkt_code || '';
if (mktc) {
setCookie('unionTypeYas', mktc, {
path: '/'
});
setCookie('mkt_code', mktc, {
path: '/'
});
}
// 尝试打开 APP
require('./common/open-app');
}());
$header.on('touchstart', 'a', function() {
... ...
... ... @@ -136,6 +136,11 @@ $submit.on('touchend', function() {
});
// 省市区
$area.on('touchend', function() {
$area.on('touchstart', function() {
addressVact.$children[0].show = true;
});
// IOS 光标隐藏
$area.find('input[name=area]').on('touchend', function() {
return false;
});
... ...
... ... @@ -46,7 +46,7 @@ function switchLoginBtnStatus() {
}
function resetForm() {
$pwd.val('').focus();
// $pwd.val('').focus();
$loginBtn.text('登录').addClass('disable');
}
... ... @@ -123,7 +123,7 @@ $loginBtn.on('touchstart', function() {
type: 'POST',
url: '/passport/login/auth',
data,
success: function(data) {
success: function(data) { //eslint-disable-line
var res,
LOGI_TYPE;
... ...
... ... @@ -86,7 +86,7 @@ $(
success: function(data) {
// 秒杀是否结束
if (data == '' || data.status === 0 || data.status === 3) {
window.location.replace('/product/show_' + $('#productSkn').val() + '.html');
window.location.replace('/product/' + $('#productSkn').val() + '.html'); // 商品url改版
// $('.sold-out').hide();
// $('.cart-bar a:first').append('<a href="javascript:;" class="sold-out">已售罄</a>');
... ...
... ... @@ -109,7 +109,7 @@ var chat = {
// 组件
this.leaveMSGView = new LeaveMSGView('#leave-msg');
this.orderListView = new OrderListView('#order-list');
this.ratingView = new RatingView('#chat-comment');
this.ratingView = new RatingView('#chat-comment', cmEntity);
const self = this;
... ... @@ -614,6 +614,9 @@ var chat = {
case allTypes.MANUAL_SERVICE:
this._manualState(chatMessage.type, rec);
break;
case allTypes.IN_QUNEUE:
this._sysInfo(chatMessage.content);
break;
case allTypes.CS_CHANGE_STATE:
if (msgType === 5) { // 重复登陆
this._sysInfo(chatMessage.content);
... ...
... ... @@ -29,6 +29,7 @@ var config = {
TRANS_REQ_ANSWER: 10007, // 收到他人对自己转移请求的反馈
SUC_DISTRIBUTE: 10009, // 客服管理员收到会话分配成功的回执
CS_CHATTING: 5000000, // 客服管理员收到会话分配成功的回执
IN_QUNEUE: 777777, // 队列中发送消息后收到的反馈
OFFLINE: 999999999, // 断线
OP_LEAVE: 999999998 // 对方离开
},
... ... @@ -48,6 +49,7 @@ var config = {
userName: '', // 用户账号
csId: 0, // 客服 ID
type: 1, // type => [0:没人在线,1:排队,2:接通,3:管理员分配]
version: '',
serviceSortId: 0,
serviceSortCode: '',
customerSettingId: 0,
... ...
... ... @@ -86,6 +86,11 @@ let api = {
saveEvalute: function(data) {
data.uid = uid;
return $.post('/service/im/saveEvalute', data);
},
// 获取评价原因
queryReasons: function(data) {
return $.get('/service/im/queryReasons', data);
}
};
... ...
... ... @@ -87,14 +87,16 @@ LeaveMSGView.prototype.constructer = LeaveMSGView;
/*
评价view
*/
const RatingView = function(elem, socket) {
const RatingView = function(elem, cmEntity) {
this.elem = $(elem);
this.$ranks = this.elem.find('.stars i');
this.$label = this.elem.find('.rank');
this.$more = this.elem.find('.more-comment');
this.cmEntity = cmEntity;
this.rank = 3;
this.bindEvents();
this.socket = socket;
this.isSending = false;
this.reasonsRendered = false;
};
RatingView.prototype = $.extend({}, EventEmitter.prototype, {
... ... @@ -110,7 +112,66 @@ RatingView.prototype = $.extend({}, EventEmitter.prototype, {
self.rating(starVal);
})
.on('click.RatingView.close', '.close', $.proxy(this.toggle, this, false));
.on('click.RatingView.close', '.close', $.proxy(this.toggle, this, false))
.on('moreComment.toggle', '.more-comment', function(event, starVal) {
let $this = $(this);
let visible = $this.is(':visible');
if (starVal < 3 && visible) {
return;
}
$this.find('.words-to-say').val('');
$this.find('.cause span').removeClass('select');
if (starVal < 3) {
let cvId = self.cmEntity.conversationId;
return self.renderReasons(cvId);
}
$this.hide();
})
.on('click.CauseItem.SelectToggle', '.cause span', function() {
let $this = $(this);
$this.toggleClass('select');
});
},
renderReasons(cvId) {
let self = this;
if (self.reasonsRendered) {
self.$more.show();
return;
}
// 评价原因渲染
api.queryReasons({
conversationId: cvId
})
.done(res => {
if (res && res.code === 200) {
let $html;
let cause = [];
res.data.forEach((item) => {
cause.push(`<span data-id="${item.id}">${item.content}</span>`);
});
$html = cause.join('');
self.$more.find('.cause').append($html);
self.reasonsRendered = true;
self.$more.show();
return;
}
tip.show('拉取评价原因失败');
})
.fail(()=> {
tip.show('拉取评价原因失败');
});
},
rating(starVal) {
... ... @@ -130,6 +191,9 @@ RatingView.prototype = $.extend({}, EventEmitter.prototype, {
this.$ranks.toggleClass(index => {
return index <= starVal ? 'rated' : null;
});
// added for customer service v1.2 optimization
this.$more.trigger('moreComment.toggle', starVal);
},
post(data) {
... ... @@ -144,9 +208,18 @@ RatingView.prototype = $.extend({}, EventEmitter.prototype, {
var params = {
stars: ++this.rank,
promoter: 1,
reasonIds: '',
reasonMsg: elem.find('.words-to-say').val(),
};
let temp = [];
let $select = self.$more.find('.cause span.select');
[].forEach.call($select, (item) => {
temp.push($(item).data('id'));
});
params.reasonIds = temp.join(':');
Object.assign(params, data);
api.saveEvalute(params)
... ...
@import "layout/img-check";
.check-page {
margin: 20px auto;
width: 700px;
.submit {
width: 100%;
height: 100px;
line-height: 100px;
text-align: center;
font-size: 32px;
color: #fff;
background: #5cb85c;
border-radius: 10px;
}
}
... ...
... ... @@ -18,7 +18,7 @@
.top {
margin-bottom: 1PX;
font-size: 34px;
font-size: 26px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
... ... @@ -30,7 +30,7 @@
}
.swiper-container {
padding: 30px 0 0px;
padding: 30px 0 0;
width: 100%;
height: 209px;
overflow-y: hidden;
... ...
... ... @@ -12,7 +12,6 @@
&-inner {
position: absolute;
bottom: 0;
height: 586px;
width: 100%;
background: #fff;
padding: 0 30px;
... ... @@ -61,10 +60,39 @@
color: #b0b0b0;
}
.cause {
font-size: 0;
span {
position: relative;
display: inline-block;
margin: 10px;
width: 328px;
width: calc(50% - 20px);
font-size: 28px;
border: 1px solid #000;
line-height: 70px;
text-align: center;
border-radius: 5px;
}
.select:after {
position: absolute;
bottom: -1px;
right: -1px;
width: 30px;
height: 30px;
content: "";
display: inline-block;
background: resolve("service/chat/cause-select.png");
background-size: cover;
}
}
.words-to-say {
height: 110px;
width: 100%;
margin: 50px 0 0;
margin: 10px 0 0;
padding: 16px;
resize: none;
border: 1px solid #e0e0e0;
... ... @@ -74,7 +102,7 @@
.submit {
height: 85px;
width: 100%;
margin: 25px 0 0;
margin: 25px 0;
color: #fff;
background: #444;
font-size: 32px;
... ...
... ... @@ -221,17 +221,18 @@
/* 返回标题处理 */
returnTitle() {
let getTitle = '';
let streetTitle = this.street.allTitle !== '全部' ? this.street.allTitle : '';
let returnTitle = '';
if (this.supportChangeProvince) {
getTitle = this.province.allTitle +
this.city.allTitle +
this.area.allTitle +
this.street.allTitle;
streetTitle;
} else {
getTitle = this.city.allTitle +
this.area.allTitle +
this.street.allTitle;
streetTitle;
}
if (getTitle.length > 11) {
... ... @@ -325,14 +326,14 @@
id: id
}, resultData => {
/* 结果返回 */
if (resultData.length < 1) {
areaCode.val(id);
let returnTitle = this.returnTitle();
// /* 结果返回 */
// if (resultData.length < 1) {
// areaCode.val(id);
// let returnTitle = this.returnTitle();
area.val(returnTitle);
this.show = false;
}
// area.val(returnTitle);
// this.show = false;
// }
/* 数据绑定 */
switch ((id + '').length) {
... ...
... ... @@ -100,7 +100,7 @@ const formatCartGoods = (goodData, isAdvanceCart, isValid, inValidLow) => {
skn: goodData.product_skn,
name: goodData.product_name,
thumb: goodData.goods_images ? helpers.image(goodData.goods_images, 120, 160) : '',
color: goodData.color_name,
color: goodData.factory_goods_name || goodData.color_name,
size: goodData.size_name,
checked: goodData.selected === 'Y',
price: transPrice(goodData.last_vip_price),
... ... @@ -153,7 +153,7 @@ const formatCartGoods = (goodData, isAdvanceCart, isValid, inValidLow) => {
}
// 商品链接
result.link = helpers.urlFormat(`/product/show_${goodData.product_skn}.html`);
result.link = helpers.urlFormat(`/product/${goodData.product_skn}.html`); // 商品url改版
return result;
};
const procPriceGiftData = (data, promotionType) => {
... ...
... ... @@ -286,7 +286,7 @@ const formatProduct = (productData, showTags, showNew, showSale, width, height,
productData.cn_alphabet = productNameProcess(productData.cn_alphabet);
}
let url = encodeURI(helpers.urlFormat(`/product/pro_${productData.product_id}_${productData.goods_list[0].goods_id}/${productData.cn_alphabet}.html`)); //eslint-disable-line
let url = encodeURI(helpers.urlFormat(`/product/${productData.product_skn}.html`));// 商品url改版
result.url = url.replace('http://', '//');
... ...
... ... @@ -334,7 +334,7 @@ function transformJit(packageList) {
_.forEach(packageList, (pValue, pKey) => {
result.packages[pKey] = {
packageType: '包裹' + (pKey + 1) + ':' + pValue.title
packageType: (pKey + 1) + ':' + pValue.title
};
_.forEach(pValue.goods_list, (gValue, gKey) => {
... ...
... ... @@ -165,7 +165,7 @@ exports.processProductList = (list, options) => {
product.cn_alphabet = productNameProcess(product.cn_alphabet);
}
product.url = helpers.urlFormat(`/product/pro_${product.product_id}_${product.goods_list[0].goods_id}/${product.cn_alphabet}.html`); // eslint-disable-line
product.url = helpers.urlFormat(`/product/${product.product_skn}.html`); // 商品url改版 // eslint-disable-line
// APP访问需要加附加的参数
// 备注:如果以后APP的接口太多,可以把这边参数提取出来,变成一个公共的方法来生成,便于以后管理维护
... ...