Authored by 周少峰

Merge branch 'master' into feature/couponcenter

Showing 71 changed files with 4139 additions and 95 deletions

Too many changes to show.

To preserve performance only 71 of 71+ files are displayed.

... ... @@ -33,7 +33,7 @@ exports.getNewArrival = (req, res, next) => {
let reqBody = req.body,
pageIndex = reqBody.pageIndex,
pageCount = reqBody.pageCount,
channel = reqBody.type,
channel = reqBody.type || req.yoho.channel,
goods = [],
result = {};
... ...
/**
* guang controller
* @author: lcy<chuanyang.liu@yoho.cn>
* @date: 2016/08/31
*/
'use strict';
let _ = require('lodash');
class Pagination {
constructor() { // url, page, totalRecords, pageSize
let options = {};
let len = arguments.length;
let args = [].slice.call(arguments);
let _pageSize = 0;
if (args.length && _.isPlainObject(args[len - 1])) {
options = args.pop();
}
this.baseUrl = args.shift() || options.baseUrl;
this.page = args.shift() || 1;
this.totalRecords = args.shift() || 0;
_pageSize = args.shift() || options.pageSize;
this.pageSize = _pageSize || 10;
this.totalPages = options.totalPages || 0;
this.theme = options.theme || 'full';
this.pageVar = options.pageVar || 'page';
this.pageSizeVar = options.pageSizeVar || 'pageSize';
if (!this.totalPages && this.totalRecords) {
this.totalPages = Math.ceil(this.totalRecords / this.pageSize);
}
this.base = this.baseUrl + (this.baseUrl.indexOf('?') < 0 ? '?' : '&') +
(_pageSize ? (this.pageSizeVar + '=' + this.pageSize + '&') : '') +
this.pageVar + '=';
}
hasNextPage() {
return this.page < this.totalPages;
}
hasPrevPage() {
return this.page > 1;
}
getUrl(page) {
return this.base + page || 1;
}
}
module.exports = Pagination;
... ...
/**
* guang controller
* @author: lcy<chuanyang.liu@yoho.cn>
* @date: 2016/08/31
*/
'use strict';
const _ = require('lodash');
const guangModel = require('../models/index');
const headerModel = require('../../../doraemon/models/header');
const ghelper = require('../models/guang-helper');
const querystring = require('querystring');
/**
* 首页文章列表 类型列表
*/
exports.index = (req, res, next) => {
let channel = req.yoho.channel;
let page = req.query.page || 1;
let pageSize = req.query.pageSize || 20;
let type = req.query.type || 0;
let pathNav = guangModel.getPathNav(channel);
let uid = req.user.uid;
let udid = ghelper.getUdid(req, res);
let gender = ghelper.getGenderByCookie(req);
Promise.all([
guangModel.getBanner(channel),
guangModel.getCategory(type, channel),
guangModel.getArticleList(gender, type, uid, udid, page, '', '', pageSize, channel, true),
guangModel.getHotTags(page, pageSize, channel),
guangModel.getAds(channel),
guangModel.getRecoArticles(gender, 1, 10, channel),
headerModel.requestHeaderData(channel)
]).then(ret => {
res.render('guang/index', {
title: '逛' + (res.locals.title || ''),
guang: {
slider: ret[0],
msgTypes: ret[1],
msgs: ret[2] && ret[2].msgs,
hotTags: ret[3],
ads: ret[4],
exRecos: ret[5],
guangIndexPage: true,
pageSize: pageSize,
type: type,
pathNav: pathNav,
baseUrl: `?${querystring.stringify(req.query)}`,
page: page,
total: (ret[2] && ret[2].total) || 0
},
module: 'guang',
page: 'guang',
headerData: ret[6] && ret[6].headerData
});
}).catch(next);
};
/**
* 指定标签的文章列表
*/
exports.tags = (req, res, next) => {
let query = req.query.query;
let page = req.query.page || 1;
let pageSize = req.query.pageSize || 20;
let type = req.query.type || 0;
let uid = req.user.uid;
let udid = ghelper.getUdid(req, res);
let gender = ghelper.getGenderByCookie(req);
let channel = req.yoho.channel;
let pathNav = guangModel.getPathNav(channel, query);
Promise.all([
guangModel.getBanner(channel),
guangModel.getArticleList(gender, 0, uid, udid, page, query, '', pageSize, channel, true),
guangModel.getHotTags(1, 20, channel),
guangModel.getAds(channel),
guangModel.getRecoArticles(gender, 1, 10, channel),
headerModel.requestHeaderData(channel)
]).then(ret => {
res.render('guang/tag', {
title: query + (res.locals.title || ''),
guang: {
slider: ret[0],
msgs: ret[1] && ret[1].msgs,
hotTags: ret[2],
ads: ret[3],
exRecos: ret[4],
tag: query,
guangIndexPage: true,
baseUrl: `?${querystring.stringify(req.query)}`,
pageSize: pageSize,
type: type,
pathNav: pathNav,
page: page,
total: (ret[1] && ret[1].total) || 0
},
module: 'guang',
page: 'list',
headerData: ret[5] && ret[5].headerData
});
}).catch(next);
};
/**
* 作者文章列表
*/
exports.editor = (req, res, next) => {
let authorId = req.query.author_id;
let channel = req.yoho.channel;
let gender = ghelper.getGenderByCookie(req);
let uid = req.user.uid;
let udid = ghelper.getUdid(req, res);
let pathNav = guangModel.getPathNav(channel);
let page = req.query.page || 1;
let pageSize = req.query.pageSize || 20;
Promise.all([
guangModel.getAuthor(authorId),
guangModel.getArticleList(gender, null, uid, udid, page, '', authorId, pageSize, channel, true),
guangModel.getHotTags(1, 20, channel),
guangModel.getAds(channel),
guangModel.getRecoArticles(gender, 1, 10, channel),
headerModel.requestHeaderData(channel)
]).then(ret => {
res.render('guang/editor', {
title: _.get(ret[0], 'name', '') + (res.locals.title || ''),
guang: {
editor: ret[0],
msgs: ret[1] && ret[1].msgs,
hotTags: ret[2],
ads: ret[3],
exRecos: ret[4],
gender: gender,
baseUrl: `?${querystring.stringify(req.query)}`,
pageSize: pageSize,
pathNav: pathNav,
page: page,
total: (ret[1] && ret[1].total) || 0
},
module: 'guang',
page: 'list',
headerData: ret[5] && ret[5].headerData
});
}).catch(next);
};
/**
* 文章详情
*/
exports.detail = (req, res, next) => {
let id = req.params.id || req.query.id;
let page = req.query.page || 1;
let pageSize = req.query.pageSize || 10;
let col = req.query.col || 0;
let pjax = req.query._pjax;
let uid = req.user.uid;
let udid = ghelper.getUdid(req, res);
let gender = ghelper.getGenderByCookie(req);
let channel = req.yoho.channel;
if (!_.isNumber(id)) {
id = parseInt(id);
}
if (pjax) {
guangModel.getArticleComments(id, page, pageSize).then(ret => {
res.render('guang/detail-comment', {
layout: false,
comment: ret
}, function(err, html) {
if (err) {
return res.send('');
}
return res.status(200).send(html);
});
});
return;
}
// 登陆后自动收藏
if (col === 1 && uid > 0) {
guangModel.collectArticle(id, uid);
}
guangModel.getArticleInfo(id, channel).then(info => {
// 判断参数是否有效, 无效会跳转到错误页面
if (!info || !info.title) {
return new Error('文章不存在');
}
let promises = [
headerModel.requestHeaderData(channel),
guangModel.getArticleContent(id),
guangModel.getHotTags(1, 20, channel),
guangModel.getArticleComments(id, page, pageSize),
guangModel.getArticleBaseInfo(id, uid, udid),
guangModel.getArticleRelateBrand(id),
guangModel.getRecoArticles(gender, 1, 10, channel),
guangModel.getAds(channel)
];
if (info.authorId) {
promises.push(guangModel.getAuthor(info.authorId));
} else {
promises.push({});
}
if (info.tag) {
promises.push(guangModel.getRelateArticleList(id, info.tag, 2, channel));
} else {
promises.push({});
}
let pathNav = guangModel.getPathNav(channel, info.title);
Promise.all(promises).then(ret => {
res.render('guang/detail', Object.assign({
module: 'guang',
page: 'detail',
headerData: ret[0] && ret[0].headerData,
guang: {
pathNav: pathNav,
id: id,
header: Object.assign({}, info, ret[8] || {},
{ commentNum: _.get(ret[3], 'commentNum', 0) }),
content: ret[1],
hotTags: ret[2],
comment: ret[3],
commentInfo: req.session['comment_' + udid],
userInfo: ret[4],
brands: ret[5],
tag: info.tags,
relatedPost: (ret[9] && ret[9].length) ? ret[9] : false,
exRecos: ret[6],
ads: ret[7],
// 分享
shareImg: info.shareImg,
sharedTitle: info.title,
shareDesc: info.desc,
weixinUrl: info.weixinUrl
}
}, {
title: `${info.title} | YOHO!BUY有货 | 年轻人潮流购物中心,中国潮流购物风向标,官方授权正品保证`,
keywords: ['Yoho! 有货,潮流,时尚,流行,购物,B2C,正品,购物网站,网上购物,货到付款,品牌服饰,男士护肤,',
'黑框眼镜,匡威,板鞋,i.t,izzue,5cm,eastpak,vans,lylescott,g-shock,new balance,lacoste,melissa,',
'casio,卡西欧手表,舒雅,jasonwood,odm,AAAA,香港购物,日本潮流'].join(''),
description: '潮流商品搜索,上衣,衬衫,TEE,卫衣,冲锋衣,风衣,羽绒服,裤子,休闲鞋,板鞋,配饰,复古眼镜',
webNavHeader: channel
}));
}).catch(next);
});
};
/**
* 列表页(列表首页、标签列表页、作者列表页)动态数据,如:查看数,点赞数,评论数,是否点赞,是否回复
* @param req
* @param res
*/
exports.listDynamicData = (req, res) => {
let ids = req.query.ids;
let udid = ghelper.getUdid(req, res);
let other = {};
let query = req.query.query,
type = req.query.type;
if (req.user.uid) {
other.uid = req.user.uid;
}
if (query) {
other.query = query;
}
if (type) {
other.type = type;
}
guangModel.getDynamicDataByIds(ids, udid, other).then(ret => {
res.send(ret);
});
};
/**
* 详情页动态数据,如:评论数,回复数,是否点赞,是否收藏
* @param req
* @param res
*/
exports.detailDynamicData = (req, res) => {
let id = req.query.id,
uid = req.user.uid,
udid = ghelper.getUdid(req, res);
guangModel.getDynamicDataById(id, uid, udid).then((ret) => {
res.status(200).send(ret);
}).catch(() => {
res.status(400);
});
};
/**
* 添加评论
*/
exports.comment = (req, res) => {
let id = req.body.id || req.query.id;
let uid = req.user.uid;
let udid = ghelper.getUdid(req, res);
let comment = req.body.comment;
// let pageSize = req.query.pageSize || 20;
if (!uid) {
req.session['comment_' + udid] = comment;
return res.send({
code: 401
});
}
guangModel.addComment(id, uid, comment).then(() => {
if (req.session['comment_' + udid]) {
req.session['comment_' + udid] = null;
}
return guangModel.getArticleComments(id, 1, 20);
}).then(commentInfo => {
res.render('guang/detail-comment', {
comment: commentInfo,
layout: false
}, (err, content) => {
if (err) {
return res.send({
code: 401
});
}
return res.send({
code: 200,
data: {
count: commentInfo.commentNum,
content: content
}
});
});
}).catch(() => {
return res.send({
code: 400,
message: '评论失败'
});
});
};
/**
* 赞
*/
exports.praise = (req, res) => {
let id = req.body.id || req.query.id;
// let uid = req.user.uid;
let udid = ghelper.getUdid(req, res);
guangModel.praise(id, udid).then(ret => {
res.send(ret);
}).catch(() => {
res.send({
code: 400
});
});
};
/**
* 取消赞
*/
exports.cancelPraise = (req, res) =>{
let id = req.body.id || req.query.id;
let udid = ghelper.getUdid(req, res);
guangModel.cancelPraise(id, udid).then(ret => {
res.send(ret);
}).catch(() => {
res.send({
code: 400
});
});
};
/**
* 收藏
*/
exports.collect = (req, res) =>{
let id = req.body.id || req.query.id;
let uid = req.user.uid;
if (!uid) {
return res.send({
code: 401
});
}
guangModel.collect(id, uid).then(ret => {
res.send(ret);
}).catch(() => {
res.send({
code: 400,
message: '收藏失败'
});
});
};
/**
* 取消收藏
*/
exports.cancelCollect = (req, res) =>{
let id = req.body.id || req.query.id;
let uid = req.user.uid;
if (!uid) {
return res.send({
code: 401
});
}
guangModel.cancelCollect(id, uid).then(ret => {
res.send(ret);
}).catch(() => {
res.send({
code: 400,
message: '取消收藏失败'
});
});
};
... ...
/**
* guang
* @author: lcy<chuanyang.liu@yoho.cn>
* @date: 2016/09/01
*/
'use strict';
let exphbs = require('express-handlebars').create(),
Handlebars = exphbs.handlebars;
Handlebars.registerHelper('json', function(json) {
return new Handlebars.SafeString(JSON.stringify(json));
});
module.exports = exphbs.handlebars;
... ...
/**
* guang
* @author: lcy<chuanyang.liu@yoho.cn>
* @date: 2016/09/01
*/
'use strict';
let _ = require('lodash');
let Handlebars = require('handlebars');
let ALL_TYPES = {
stand: 'p-page-n',
mini: 'p-n',
full: 'f-p-page-n-l-info-input-gobtn',
fullellipsis: 'f-p-pe-n-l-info-input-gobtn',
ellipsis: 'p-pe-n'
};
exports.pager = function() {
let options = arguments[arguments.length - 1];
let baseUrl = (arguments.length > 1 ? arguments[0] : null) || options.hash.baseUrl || '',
page = (options.hash.page || 1) * 1,
showNum = (options.hash.showNum || 7) * 1,
pageSize = options.hash.pageSize || 20,
totalPages = options.hash.totalPages,
totalRecords = options.hash.totalRecords,
theme = options.hash.theme || 'pager',
currentClass = options.hash.currentClass || 'cur',
// min full stand ellipsis or: f-首页, p-上一页, page-页码,n-下一页,l-最后一页,info-displayMsg,inout输入框,gobtn-goto Btn
type = options.hash.type || 'stand',
pageVar = options.hash.pageVar || 'page',
pageSizeVar = options.hash.pageSizeVar || 'pageSize';
// 清除原来page(page=1&) 重新定义page
let clearPageReg = new RegExp(pageVar + '=[^&]*(&|$)'),
clearSizeReg = new RegExp(pageSizeVar + '=[^&]*(&|$)'),
base = baseUrl.replace(clearPageReg, '');
if (options.hash.pageSize) {
base = base.replace(clearSizeReg, '');
}
base += (base.indexOf('?') < 0 ? '?' : (base.charAt(base.length - 1) !== '?' ? '&' : '')) +
(options.hash.pageSize ? (pageSizeVar + '=' + pageSize + '&') : '') +
pageVar + '=';
function getPageNums(ntype) {
var pageNums = [];
var num = showNum;
if (ntype === 'e') {
num = num - 2;
num = num > 2 ? num : 2;
}
/** 分页展示页码个数begin 规则:展示最靠近当前页的指定个数 **/
let pageShowMax = num % 2 === 0 ? page - 1 : page;
let pageShowMin = page;
for (let i = 0; i < Math.floor(num / 2); i++) {
pageShowMax++;
pageShowMin--;
if (pageShowMax > totalPages) {
pageShowMax = totalPages;
if (pageShowMin > 1) {
pageShowMin--;
}
}
if (pageShowMin < 1) {
pageShowMin = 1;
if (pageShowMax < totalPages) {
pageShowMax++;
}
}
}
for (let n = pageShowMin; n <= pageShowMax; n++) {
pageNums.push(n);
}
if (ntype === 'e') {
if (pageShowMin > 3) {
pageNums.unshift(1, '.');
} else if (pageShowMin === 2) {
pageNums.unshift(1);
} else if (pageShowMin === 3) {
pageNums.unshift(1, 2);
}
if (pageShowMax < totalPages - 2) {
pageNums.push('.', totalPages);
} else {
for (let x = pageShowMax + 1; x <= totalPages; x++) {
pageNums.push(x);
}
}
}
return pageNums;
}
function renderItem(arr) {
/** 分页展示页码个数end **/
let ret = '';
if (_.isArray(arr) && arr.length) {
arr.forEach((val) => {
if (val === '.') {
ret += '<a>...</a>';
} else {
ret += `<a href="${base}${val}" ` +
(page === val ? `class="${currentClass}"` : '') +
` title="第${val}页">${val}</a>`;
}
});
}
return ret;
}
function createStandItems() {
return renderItem(getPageNums());
}
function createEllipsisItems() {
return renderItem(getPageNums('e'));
}
if (!totalPages) {
if (!totalRecords || !pageSize) {
return new Handlebars.SafeString('');
} else {
totalPages = Math.ceil(totalRecords / pageSize);
}
}
let items = ALL_TYPES[type] ? ALL_TYPES[type] : type;
items = _.isArray(items) ? items : (items || ALL_TYPES.stand).split('-');
let hasPage = false; // 配置中如果配置了多次 page/pe 则将忽略,只第一次有效
let ret = `<div class="pager ${theme}">`;
items.forEach(function(val) {
switch (val) {
case 'f' :
if (page > 1) {
ret += `<a href="${base}1" title="首页">首页</a>`;
}
break;
case 'p' :
if (page > 1) {
ret += `<a href="${base}` + (page - 1) +
'" title="上一页"><span class="iconfont">&#xe60e;</span>上一页</a>';
}
break;
case 'n' :
if (page < totalPages) {
ret += `<a href="${base}` + (page + 1) +
'" title="下一页">下一页<span class="iconfont">&#xe60c;</span></a>';
}
break;
case 'l' :
if (page < totalPages) {
ret += `<a href="${base}${totalPages}" title="尾页">尾页</a>`;
}
break;
case 'info' :
ret += '共{totalRecords}条/{totalPages}页';
break;
case 'input' :
// input
// ret += '<span class="{cls}"><input value="{value}" type="text"></span>';
break;
case 'gobtn' :
// goto btn
break;
case 'page' :
if (!hasPage) {
ret += createStandItems();
}
hasPage = true;
break;
case 'pe' :
if (!hasPage) {
ret += createEllipsisItems();
}
hasPage = true;
break;
}
});
if (options.fn) {
ret += options.fn(options.context);
}
ret += '</div>';
return new Handlebars.SafeString(ret);
};
... ...
/**
* guang
* @author: lcy<chuanyang.liu@yoho.cn>
* @date: 2016/08/31
*/
'use strict';
var express = require('express'),
path = require('path'),
hbs = require('express-handlebars');
var app = express();
// set view engin
var doraemon = path.join(__dirname, '../../doraemon/views'); // parent view root
var partials = path.join(__dirname, './views'); // parent view root
app.on('mount', function(parent) {
delete parent.locals.settings; // 不继承父 App 的设置
Object.assign(app.locals, parent.locals);
});
app.set('views', path.join(__dirname, 'views/action'));
app.engine('.hbs', hbs({
extname: '.hbs',
defaultLayout: 'layout',
layoutsDir: doraemon,
partialsDir: [`${partials}/partial`, `${doraemon}/partial`],
helpers: Object.assign(require('./helpers/pager'), global.yoho.helpers)
}));
// require('./helpers/json');
// require('./helpers/page');
// router
app.use(require('./router'));
module.exports = app;
... ...
/**
* 逛 model
* @author: lcy<chuanyang.liu@yoho.cn>
* @date: 2016/09/06
*/
'use strict';
const md5 = require('md5');
const requestIp = require('request-ip');
const _ = require('lodash');
const helpers = global.yoho.helpers;
/* COOKIE标识访问的是男生频道 */
// const COOKIE_NAME_BOYS = 'boys';
// const COOKIE_DOMAIN = '.yohobuy.com';
const getGenderByCookie = (req) => {
let gender = null;
let channel = req.yoho.channel;
switch (channel) {
case 'boys':
{
gender = '1,3';
break;
}
case 'girls':
{
gender = '2,3';
break;
}
default:
{
gender = '1,2,3';
}
}
return gender;
};
/**
* 获取客户端唯一标识
*
* @return string
*/
const getUdid = (req, res) => {
let udid = req.cookies.udid;
if (!udid) {
udid = md5(req.ip || requestIp.getClientIp(req));
if (res && res.cookie) {
res.cookie('udid', udid);
}
}
return udid;
};
/**
* 获得文章 url
* @param type string url 后台返回的url
* @param type id 产品编号
* @return type url
*/
const getArticleUrl = (url, id, channel) => {
/* 格式由url:{url:'aaa'} 更改为 url: 'aaa'
try {
let urlObj = JSON.parse(url);
if (urlObj && urlObj['url']) {
return urlObj['url'];
}
} catch (e) {}*/
if (_.isString(url) && _.trim(url) !== '') {
return url;
}
let param = {};
if (channel) {
param.channel = channel;
}
return helpers.urlFormat(`/${id}.html`, param, 'guang');
};
module.exports = {
getGenderByCookie,
getUdid,
getArticleUrl
};
... ...
/**
* 逛 model
* @author: lcy<chuanyang.liu@yoho.cn>
* @date: 2016/08/31
*/
'use strict';
const _ = require('lodash');
const moment = require('moment');
const ghelper = require('./guang-helper');
const helpers = global.yoho.helpers;
const serviceApi = global.yoho.ServiceAPI;
const yohoApi = global.yoho.API;
// const KEY_WEB_GUANG_BANNER_DATA = 'key_web_guang_banner_data';// 逛的首页banner
// const KEY_WEB_GUANG_ADS_DATA = 'key_web_guang_ads_data';// 逛的首页ads
const URL_OPERATIONS_RESOURCE_GET = 'operations/api/v5/resource/get';
// guang banner code
const BANNER_CODE = {
boys: '15a288635c2ed9f6c807417be90f5d2d',
girls: 'e14e12e35af8626650979f7af8a0de2b',
lifestyle: '1d398e899f759c6d88971be680521a6f',
kids: 'ad14ee01ad048ce308aa3ca416133d2a'
};
// 逛 ads code
const ADS_CODE = {
boys: '41777aa7ac86347692c5aa0d394b2f59',
girls: '722253573823ebb994e313e71b0a4fb9',
lifestyle: '02568b6042510e4be739cc688dc7d6ae',
kids: '1ffdd6ea22c58af52ee6408cd353c2d5'
};
/**
* 获取首页频道nav
*/
const getHomeChannelNav = (channel) => {
let home;
switch (channel) {
case 'girls':
home = helpers.urlFormat('/woman', '', 'new');
break;
case 'lifestyle':
home = helpers.urlFormat('/lifestyle', '', 'new');
break;
case 'kids':
home = helpers.urlFormat('/kids', '', 'new');
break;
default:
home = helpers.urlFormat('', '', 'default');
}
return {
href: home,
name: `${channel.toUpperCase()}首页`,
pathTitle: 'YOHO!有货'
};
};
const getPathNav = (channelType, query) => {
let path = _.concat(
getHomeChannelNav(channelType),
[{
name: '逛',
pathTitle: '逛',
href: helpers.urlFormat('', '', 'guang')
}]
);
return query ? _.concat(path, [{ name: query, pathTitle: query}]) : path;
};
const _formatTag = (tagData, channel) => {
let name = tagData.name,
param = {
query: name
};
if (channel) {
param.channel = channel;
}
return {
tag: name,
name: name,
url: helpers.urlFormat('/tags/index', param, 'guang')
};
};
/**
* 格式化资讯文章
*
* @param array $articleData 需要格式化的资讯数据
* @param bool $showTag 是否显示左上角标签
* @param bool $showAuthor 控制是否显示作者信息
* @return array | false
*/
const _formatArticle = (articleData, showTag, showAuthor, channel) => {
// 资讯ID不存在,则不显示
if (!articleData || !articleData.id) {
return false;
}
let width = 360,
height = 360,
isSquareImage = true;
if (Number(articleData.conver_image_type) === 2) {
width = 360;
height = 240;
isSquareImage = false;
}
let result = {
id: articleData.id,
classification: articleData.category_name,
isReco: articleData.is_recommended ? true : false,
url: ghelper.getArticleUrl(articleData.url, articleData.id, channel),
img: helpers.image(articleData.src, width, height, 1),
isSquareImg: isSquareImage,
title: articleData.title,
pTime: articleData.publish_time,
pView: articleData.views_num,
content: articleData.intro,
showTags: showTag,
comment: articleData.comment_num
};
if (!articleData.author) {
articleData.author = {
name: '',
avatar: ''
};
}
result.author = articleData.author.name;
let authorId = articleData.author.author_id;
if (authorId) {
let aparam = {
author_id: authorId
};
if (channel) {
aparam.channel = channel;
}
result.editorUrl = helpers.urlFormat('/Index/editor', aparam, 'guang');
}
let tags = [];
if (articleData.tags) {
let aTags = articleData.tags;
for (let i = 0; i < aTags.length; i++) {
tags.push(_formatTag(aTags[i], channel));
}
}
result.tags = tags;
_.assign(result, {
tags: tags,
like: articleData.praise_num,
liked: articleData.isPraise === 'Y'
});
// 判断是否显示作者信息
if (showAuthor && articleData.author) {
result.author = _.cloneDeep(articleData.author);
}
// 模板中需要的标签标识
if (showTag && articleData.category_id) {
let categoryId = '' + articleData.category_id;
switch (categoryId) {
case '1': // 话题
result.isTopic = true;
break;
case '2': // 搭配
result.isCollocation = true;
break;
case '3': // 潮人
result.isFashionMan = true;
break;
case '4': // 潮品
result.isFashionGood = true;
break;
case '5': // 小贴士
result.isTip = true;
break;
default:
result.isTopic = true;
}
}
return result;
};
const _formatAd = (adData, channel) => {
if (!adData) {
return null;
}
let param = {
id: adData.id
};
if (channel) {
param.channel = channel;
}
return {
img: helpers.image(adData.src, 640, 640),
url: helpers.urlFormat('/info/index', param, 'guang'),
title: adData.title,
bgColor: adData.bgColor
};
};
/**
* 获取页文章数据
* @param {String} channelType 传入频道页类型,值可以是: boys, girls, kids, lifestyle
* @return {Object}
*/
const getArticleList = (gender, sortId, uid, udid, page, tag, authorId, limit, channel, useCache) => {
uid = uid || 0;
udid = udid || '';
page = page || 1;
useCache = useCache || false;
let param = {
gender: gender,
page: page,
uid: uid,
udid: udid,
client_type: 'web'
};
if (sortId) {
param.sort_id = sortId;
}
if (tag) {
param.tag = tag;
}
if (authorId && Number(authorId)) {
param.author_id = authorId;
}
if (limit) {
param.limit = limit;
}
return serviceApi.get('guang/api/v2/article/getList', param, {
cache: useCache ? 300 : false
}).then(res => {
if (res && res.data) {
let artList,
adsList,
total = 0;
if (res.data.total) {
total = _.parseInt(res.data.total);
}
if (res.data.list) {
let list = res.data.list;
if (list.artList) {
artList = _.map(list.artList, it => _formatArticle(it, true, false, channel));
}
if (list.adlist) {
adsList = _.map(list.artList, it => _formatAd(it, channel));
}
}
return {
msgs: artList,
ads: adsList,
total: total
};
}
return null;
});
};
/**
* 获取热门标签数据
* @param {String} type 传入频道页类型,值可以是: boys, girls, kids, lifestyle
* @return {Object}
*/
const getHotTags = (page, limit, channel) => {
let data = {
client_type: 'web',
page: page || 1,
limit: limit || 10
};
return serviceApi.get('guang/api/v2/article/getTagTop', data, {
cache: true
}).then(res => {
return _.map((res && res.data) || [], it => {
let param = {
query: it.tag_name
};
if (channel) {
param.channel = channel;
}
return {
tagName: it.tag_name,
url: helpers.urlFormat('/tags/index', param, 'guang')
};
});
});
};
/**
* 获取广告数据
* @param {String} channelType 传入频道页类型,值可以是: boys, girls, kids, lifestyle
* @return {Object}
*/
const getAds = channelType => {
let contentCode = ADS_CODE[channelType] || ADS_CODE.boys;
return serviceApi.get(URL_OPERATIONS_RESOURCE_GET, {
content_code: contentCode
}, {cache: true}).then(res => {
let list = [];
if (res && res.code === 200 && res.data && res.data[0] && res.data[0].data) {
list = _.map(res.data[0].data, (it) => {
return {
img: helpers.image(it.src, 640, 640, 1),
url: it.url
};
});
}
return list.length > 5 ? list.slice(0, 4) : list;
});
};
/**
* 获取热门标签数据
* @param {String} type 传入频道页类型,值可以是: boys, girls, kids, lifestyle
* @return {Object}
*/
const getBanner = channelType => {
let contentCode = BANNER_CODE[channelType] || BANNER_CODE.boys;
return serviceApi.get(URL_OPERATIONS_RESOURCE_GET, {
content_code: contentCode
}, {cache: true}).then(res => {
let list = [];
if (res && res.code === 200 && res.data && res.data[0] && res.data[0].data) {
list = _.map(res.data[0].data, it => {
return {
img: helpers.image(it.src, 830, 327, 1),
url: it.url
};
});
}
return list;
});
};
const getCategory = (currentSortId, channel) => {
currentSortId = currentSortId || 0;
return serviceApi.get('guang/api/v1/category/get', {}, {
cache: true
}).then(res => {
let list = [];
if (res && res.code === 200 && res.data) {
for (let cat of res.data) {
let param = {
type: cat.id
};
if (channel) {
param.channel = channel;
}
list.push({
typeId: cat.id,
type: cat.name,
isActive: String(cat.id) === String(currentSortId),
navUrl: helpers.urlFormat('/index/index', param, 'guang')
});
}
}
return list;
});
};
/**
* 推荐文章
*/
const getRecoArticles = (gender, page, limit, channel) => {
return serviceApi.get('guang/api/v2/article/getArticleByViewsNum', {
gender: gender,
page: page,
limit: limit
}, {cache: true}).then(res => {
let list = [];
if (res && res.data) {
for (let i = 0; i < res.data.length; i++) {
let it = res.data[i];
let reco = {
url: ghelper.getArticleUrl(it.url, it.id, channel),
title: it.title
};
if (it.src) {
reco.img = helpers.image(it.src, 90, 60, 1);
}
list.push(reco);
}
}
return list;
});
};
/**
* 获取作者信息
*/
const getAuthor = authorId => {
return serviceApi.get('guang/service/v1/author/getAuthor', {
author_id: authorId
}, {
cache: 3600
}).then(res => {
if (res && res.data) {
let d = res.data;
return {
authorId: authorId,
avatar: d.avatar,
name: d.name,
intro: d.author_desc,
authorUrl: d.name ? helpers.urlFormat('/Index/editor', {author_id: authorId }, 'guang') : ''
};
}
});
};
/**
* 获取文章基本信息,文章标题(不含内容)
*/
const getArticleInfo = (aid, channel) => {
return serviceApi.get('guang/service/v2/article/getArticle', {
article_id: aid
}, {cache: true}).then(res => {
if (res && res.code === 200 && res.data) {
let d = res.data;
let tags = [];
if (d.tags) {
for (let i = 0; i < d.tags.length; i++) {
tags.push(_formatTag(d.tags[i], channel));
}
}
return {
title: d.article_title,
time: moment(d.publish_time * 1000).format('YYYY年MM月DD HH:mm'),
click: d.pageViews,
shareImg: helpers.image(d.cover_image, 600, 600),
desc: d.article_summary,
authorId: d.author_id,
weixinUrl: d.url,
tag: d.tag, // tags 的字符串
tags: tags
};
}
});
};
const _formatProduct = (products, arr) => {
let result = [];
_.forEach(products, val => {
let goods = {
thumb: helpers.image(val.default_images, 235, 314),
product_name: val.product_name,
sales_price: val.sales_price,
url: helpers.getUrlBySkc(val.product_id, val.goods_list[0].goods_id, val.cn_alphabet)
};
if (val.market_price !== val.sales_price) {
goods.marketPrice = val.market_price;
}
_.forEach(arr, (v, k) => {
if (Number(k) === Number(val.product_skn)) {
goods.thumb = helpers.image(v, 235, 314);
}
});
result.push(goods);
});
return result;
};
/**
* 按照skn string 来查询 query=skn1,skn2,skn3
*/
const getProductList = (params, arr) => {
return yohoApi.get('', _.assign({
method: 'web.search.search',
order: 's_n_desc',
limit: 60
}, params), { cache: true }).then(ret => {
if (ret && ret.code === 200 && ret.data && ret.data.product_list) {
return _formatProduct(ret.data.product_list, arr);
}
});
};
const _articleContentFormat = {
goods: goods => {
let productSkn = [],
arr = {};
_.forEach(goods, val => {
productSkn.push(val.id);
arr[val.id] = val.src;
});
if (productSkn.length > 0) {
return getProductList({
query: productSkn.join(',')
}, arr);
}
return null;
},
goodsGroup: goodsGroup => {
let result = [];
_.forEach(goodsGroup, val => {
if (val && val.list) {
let productSkn = [];
let arr = {};
for (let it of val.list) {
productSkn.push(it.id);
arr[it.id] = it.src;
}
if (productSkn.length) {
// 包含多个对象,每对象里list都取数据,最终每个list只取前4个
result.push(getProductList({
query: productSkn.join(',')
}, arr).then(products => {
let pl = [];
if (products && _.isArray(products)) {
pl = products.slice(0, 4);
}
return pl;
}));
}
}
});
return result;
},
text: data => {
return data;
},
singleImage: data => {
if (data && data[0] && data[0].src) {
return {
pic: helpers.image(data[0].src, 640, 640)
};
}
return null;
},
smallPic: data => {
let result = {
smallPic: []
};
_.forEach(data, (it, key) => {
if (key < 2) {
result.smallPic.push(helpers.image(it.src, 600, 600));
}
});
return result;
},
link: () => ({})
};
/**
* 获取文章内容详情
*/
const getArticleContent = aid => {
let content = [],
index = 0;
return serviceApi.get('guang/service/v2/article/getArticleContent', {
article_id: aid
}, {cache: true}).then(res => { // 内容内推荐的商品
let gpromises = [], ggpromises = [];
if (res && res.code === 200 && res.data) {
_.forEach(res.data, (it) => {
_.forEach(it, (val, key) => {
if (key === 'goods') {
gpromises.push(_articleContentFormat.goods(val.data));
} else if (key === 'goodsGroup') {
// 可能包含多个list,则有多个promise
ggpromises = ggpromises.concat(_articleContentFormat.goodsGroup(val.data));
} else {
let other = _.isFunction(_articleContentFormat[key]) ?
_articleContentFormat[key](val.data) : '';
content.push(other);
}
});
});
}
index = gpromises.length;
return Promise.all(gpromises.concat(ggpromises));
}).then(res => {
let goods = _.filter(_.flatten(res.slice(0, index)), function(it) {
return it;
});
let goodsGroup = _.filter(_.flatten(res.slice(index)), function(it) {
return it;
});
if (goods.length > 0) {
content.push({
relatedReco: {
recos: goods
}
});
}
if (goodsGroup.length > 0) {
content.push({
relatedReco: {
recos: goodsGroup
}
});
}
return content;
});
};
/**
* 判断用户是否收藏文章地址,应该是文章与用户关联的信息
* @param $articleId
* @param $uid
* @param $udid
* @param bool $onlyUrl
* @return mixed
*/
const getArticleBaseInfo = (aid, uid, udid) => {
return serviceApi.get('guang/api/v1/article/getArticleBaseInfo', {
id: aid,
uid: uid,
udid: udid
}).then(res => ({
isLike: res && res.isPraise === 'Y',
likeNum: res.praise_num || 0,
isCollected: res && res.isFavor === 'Y'
}));
};
/**
* 文章相关品牌
* @param $articleId
* @param bool $onlyUrl
* @return mixed
*/
const getArticleRelateBrand = aid => {
return serviceApi.get('guang/service/v2/article/getBrand', {
article_id: aid
}, {cache: true}).then(res => {
if (res && res.code === 200 && res.data) {
return _.map(res.data, it => {
it.thumb = it.thumb;
it.url = it.url;
return it;
});
}
});
};
/**
* 相关文章列表
* @param $articleId
* @param $tag
* @param int $limit
* @param bool $onlyUrl
* @return mixed
*/
const getRelateArticleList = (aid, tag, size, channel) => {
size = size || 3;
return serviceApi.get('guang/service/v2/article/getOtherArticle', {
article_id: aid,
tags: tag,
limit: size
}, {cache: true}).then(res => {
if (res && res.code === 200 && res.data) {
return _.map(res.data, it => {
it.thumb = helpers.image(it.thumb, 264, 173, 1);
it.url = ghelper.getArticleUrl(it.url, it.id, channel);
return it;
});
}
});
};
/**
* 获取文章评论数据
*/
const getArticleComments = (aid, page, pageSize) => {
page = page || 1;
pageSize = pageSize || 20;
return serviceApi.get('guang/api/v1/comments/getList', {
article_id: aid,
page: page,
limit: pageSize
}).then(res => {
let num = (res.data && res.data.total) || 0;
let list = [];
if (num > 0 && res.data.list) {
let iList = res.data.list;
for (let i = 0; i < iList.length; i++) {
let it = iList[i];
list.push({
avatar: helpers.image(it.avator, 100, 100),
name: it.username,
content: it.content,
time: it.create_time
});
}
}
return {
commentNum: num,
pageSize: pageSize,
page: page,
list: list,
baseUrl: helpers.urlFormat('/info/index', {
id: aid,
pageSize: pageSize
}, 'guang')
};
});
};
/**
* 文章评论提交
* @param $id
* @param $uid
* @return mixed
*/
const addComment = (aid, uid, content) => serviceApi.get('guang/api/v1/comments/add', {
article_id: aid,
uid: uid,
content: content
}).then(res => {
if (res && res.code === 200) {
return res.data;
} else {
return Promise.reject('评论失败');
}
});
/**
* 文章点赞
* @param $id
* @param $uid
* @return mixed
*/
const praise = (aid, udid) => serviceApi.get('guang/api/v2/praise/setPraise', {
article_id: aid,
udid: udid
});
/**
* 文章点赞
* @param $id
* @param $uid
* @return mixed
*/
const cancelPraise = (aid, udid) => serviceApi.get('guang/api/v2/praise/cancel', {
article_id: aid,
udid: udid
});
/**
* 收藏文章
* @param $id
* @param $uid
* @return mixed
*/
const collect = (aid, uid) => serviceApi.get('guang/api/v1/favorite/setFavorite', {
article_id: aid,
uid: uid
});
/**
* 取消收藏文章
* @param $id
* @param $uid
* @return mixed
*/
const cancelCollect = (aid, uid) => serviceApi.get('guang/api/v1/favorite/cancelFavorite', {
article_id: aid,
uid: uid
});
/**
* 获取制指定文章的动态信息
* @param ids
* @returns {Promise.<T>|*}
*/
const getDynamicDataById = (id, uid, udid) => {
return serviceApi.get('guang/api/*/article/getArticlePraiseAndFavor', {
id: id,
uid: uid,
udid: udid
});
};
/**
* 获取制指定文章的动态信息
* @param ids
* @param udid
* @param other [Obejct] 包含uid,query,type等非必传参数
* @returns {Promise.<T>|*}
*/
const getDynamicDataByIds = (ids, udid, other) => {
let params = {
articleIds: ids,
udid: udid
};
if (other.uid) {
_.assign(params, {
uid: other.uid
});
}
if (other.query) {
_.assign(params, {
query: other.query
});
}
if (other.type) {
_.assign(params, {
type: other.type
});
}
return serviceApi.get('guang/api/*/article/getSimpleArticleList', params, {cache: true});
};
module.exports = {
getArticleList,
getHotTags,
getAds,
getBanner,
getCategory,
getRecoArticles,
getPathNav,
getAuthor,
getArticleInfo,
getArticleContent,
getArticleBaseInfo,
getArticleRelateBrand,
getRelateArticleList,
getArticleComments,
addComment,
praise,
cancelPraise,
collect,
cancelCollect,
getDynamicDataById,
getDynamicDataByIds
};
... ...
/**
* router of guang
* @author: lcy<chuanyang.liu@yoho.cn>
* @date: 2016/08/31
*/
'use strict';
const router = require('express').Router(); // eslint-disable-line
const cRoot = './controllers';
const guangController = require(`${cRoot}/index`);
router.get(['/', '/index/index'], guangController.index);
router.get(['/detail/:id', '/info/index'], guangController.detail); // guang/info/index
router.get('/tags/index', guangController.tags);
router.get('/Index/editor', guangController.editor);
// ajax
router.post('/info/comment', guangController.comment); // 添加评论
router.get('/info/praise', guangController.praise); // 点赞
router.get('/info/cancelPraise', guangController.cancelPraise);
router.get('/info/collect', guangController.collect);
router.get('/info/cancelCollect', guangController.cancelCollect);
router.get('/info/listData', guangController.listDynamicData);
router.get('/info/detailData', guangController.detailDynamicData);
// router.get('/info/commentData', guangController.detailCommentData);
module.exports = router;
... ...
{{> comment}}
\ No newline at end of file
... ...
<div class="guang-detail-page guang-page yoho-page clearfix">
{{# guang}}
{{> common/path-nav}}
<div class="left-side detail-body" data-id="{{id}}">
{{# header}}
<div class="detail-title">{{title}}</div>
<div class="article-info clearfix">
<div class="article-author">
<div class="author-avatar">
<a href="{{authorUrl}}" target="_blank">
<img src="{{avatar}}">
</a>
</div>
</div>
<div class="author-info">
<a class="author-name" href="{{authorUrl}}">{{name}}</a>
</div>
<div class="article-status clearfix">
<span class="article-time">{{time}}</span>
<span class="article-click">点击:<em>{{click}}</em></span>
<a href="#comment-info" id="article-comment" class="article-comment"><em class="comment-num">{{commentNum}}</em>条评论</a>
</div>
</div>
{{/ header}}
<div class="article-main">
{{# content}}
{{# pic}}
<div class="article-pic block">
<img class="lazy" data-original="{{.}}">
</div>
{{/ pic}}
{{# text}}
<div class="article-text block">
<p>{{{.}}}</p>
</div>
{{/ text}}
{{#if smallPic}}
<div class="article-small-pic block clearfix">
{{# smallPic}}
<img class="lazy" data-original="{{.}}">
{{/ smallPic}}
</div>
{{/if}}
{{# relatedReco}}
<div class="related-reco block clearfix">
<div class="block-header">
相关推荐
{{# moreReco}}
<a class="more-reco" href="{{.}}">MORE ></a>
{{/ moreReco}}
</div>
<div class="recos clearfix">
{{# recos}}
{{> product/good}}
{{/ recos}}
</div>
</div>
{{/ relatedReco}}
{{/ content}}
</div>
{{#if brands}}
<div class="related-brand block clearfix">
<div class="block-header">相关品牌</div>
<div class="brands">
{{# brands}}
<div class="brand">
<a class="thumb" href="{{url}}" target="_blank">
<img class="lazy" data-original="{{thumb}}">
</a>
<p class="brand-name">{{name}}</p>
</div>
{{/ brands}}
</div>
</div>
{{/if}}
{{# userInfo}}
<div class="user-handle">
<ul class="clearfix">
<li id="prise-btn" class="like-status{{#isLike}} liked{{/isLike}}">
<a href="javascript:;">
<i class="iconfont">&#xe626;</i>
<span class="like-num">{{likeNum}}</span>
</a>
</li>
<li id="collect-btn" class="sort-collect{{#isCollected}} collected{{/isCollected}}">
<a href="javascript:;">
<i class="iconfont">&#xe611;</i>
<span>收藏</span>
<span class="cancel-collect">取消收藏</span>
</a>
</li>
</ul>
</div>
{{/ userInfo}}
<div class="article-bottom-info clearfix">
{{#if tag}}
<div class="article-tag clearfix">
<i class="tag-icon iconfont">&#xe624;</i>
<ul class="clearfix">
{{# tag}}
<li>
<a href="{{url}}" target="_blank">{{name}}</a>
</li>
{{/ tag}}
</ul>
</div>
{{/if}}
<div class="article-share">
<span class="title pull-left">分享至:</span>
{{> share}}
</div>
</div>
{{#if relatedPost}}
<div class="detail-related-posts">
<ul class="clearfix">
{{# relatedPost}}
<li>
<a href="{{url}}" target="_blank">
<span class="bg-img">
<img src="{{thumb}}" alt="">
</span>
<div class="post-title">
<h2>{{title}}</h2>
</div>
</a>
</li>
{{/ relatedPost}}
</ul>
</div>
{{/if}}
<div id="comment-area" class="comment-area">
<div class="comment-textarea">
<textarea id="comment-info" placeholder="我有话要说。。。">{{commentInfo}}</textarea>
</div>
<div class="comment-publish clearfix">
<span id="word-count-tip" class="word-count-tip"></span>
<a id="comment-btn" class="publish-btn disable">评论</a>
</div>
<div id="pjax-container" class="comments-wrap">
{{> comment}}
</div>
</div>
</div>
<div class="right-side detail-side">
{{> right-side}}
</div>
{{/ guang}}
</div>
... ...
<div class="guang-editor-page guang-page yoho-page clearfix">
{{# guang}}
{{> common/path-nav}}
{{# editor}}
<div class="editor-info clearfix">
<div class="author-avatar">
<img src="{{avatar}}" alt="">
</div>
<div class="author-info">
<p class="author-name">{{name}}</p>
<p class="author-introduce">{{intro}}</p>
</div>
</div>
{{/ editor}}
<div class="left-side">
<div id="msg-list" class="msg-list">
{{# msgs}}
{{> msg}}
{{/ msgs}}
</div>
<div class="msg-pager pager">
{{pager baseUrl totalRecords=total page=page type="ellipsis" theme="msg-pager"}}
</div>
</div>
<div class="right-side">
{{> right-side}}
</div>
{{/ guang}}
</div>
... ...
<div class="guang-index-page guang-page yoho-page clearfix">
{{# guang}}
{{> common/path-nav}}
<div class="left-side">
<div id="slider" class="slider">
<ul class="slide-wrapper">
{{#each slider}}
<li>
<a href="{{url}}" target="_blank">
{{#if @first}}
<img src="{{img}}">
{{^}}
<img class="lazy" data-original="{{img}}">
{{/if}}
</a>
</li>
{{/each}}
</ul>
</div>
<div id="pjax-container" class="msg">
<ul class="msg-nav">
{{# msgTypes}}
<li data-type="{{typeId}}" {{#if isActive}}class="actived"{{/if}}>
<a class="pjax-link" href="{{navUrl}}">{{type}}</a>
</li>
{{/ msgTypes}}
</ul>
<div id="msg-list" class="msg-list">
{{# msgs}}
{{> msg}}
{{/ msgs}}
</div>
{{pager baseUrl totalRecords=total page=page type="ellipsis" theme="msg-pager"}}
</div>
</div>
<div class="right-side">
{{> right-side}}
</div>
{{/ guang}}
</div>
... ...
<div class="guang-list-page guang-page yoho-page clearfix">
{{# guang}}
{{> common/path-nav}}
<div class="left-side">
<div class="tag-header">
<span>{{tag}}</span>
关联的文章
</div>
<div id="msg-list" class="msg-list">
{{# msgs}}
{{> msg}}
{{/ msgs}}
</div>
{{pager baseUrl totalRecords=total page=page type="ellipsis" theme="msg-pager"}}
</div>
<div class="right-side">
{{> right-side}}
</div>
{{/ guang}}
</div>
... ...
{{# comment}}
<h4>
<span class="comment-num">{{commentNum}}</span>
条评论 <i></i>
</h4>
<p class="comments-empty">还没有评论,快抢沙发吧</p>
<div class="commnets-resultwrapper">
<ul class="comments-list">
{{# list}}
<li class="clearfix">
<div class="avatar">
<img class="comment-user-avatar" src="{{avatar}}" alt=""></div>
<div class="comment-info">
<p class="comment-user-name">{{name}}</p>
<p class="comment-content">{{content}}</p>
<p class="comment-time">{{time}}</p>
</div>
</li>
{{/ list}}
</ul>
<div class="comment-pager pager">{{pager baseUrl totalRecords=commentNum page=page pageSize=pageSize type="ellipsis" theme="msg-pager"}}</div>
</div>
{{/ comment}}
... ...
<div class="msg-content clearfix" data-id="{{id}}">
<div class="msg-img">
<div class="classification">
{{classification}}
</div>
{{#if isReco}}
<div class="reco"></div>
{{/if}}
<a href="{{url}}" target="_blank">
<img class="lazy{{#if isSquareImg}} square{{/if}}" data-original="{{img}}">
</a>
</div>
<div class="msg-info">
<a class="msg-title" href="{{url}}" target="_blank">{{title}}</a>
<p class="msg-app">
<a href="{{editorUrl}}" target="_blank">
<span class="author">{{author}}</span>
</a>
<span class="publish-time">
<i class="iconfont">&#xe625;</i>
{{pTime}}
</span>
<span class="page-view">
<i class="iconfont">&#xe627;</i>
<em>{{pView}}</em>
</span>
</p>
<p class="content">{{content}}</p>
<div class="footer">
<div class="tags">
{{# tags}}
<a class="msg-tag" href="{{url}}" target="_blank">{{tag}}</a>
{{/ tags}}
</div>
<div class="like-comment">
<span class="like">
<i class="iconfont like-icon{{#if liked}} liked{{/if}}">&#xe626;</i>
{{#if like}}<b class="like-num">(<em class="num">{{like}}</em>)</b>{{/if}}
</span>
<span class="comment">
<i class="iconfont">&#xe624;</i>
{{# comment}}
(<em>{{.}}</em>)
{{/ comment}}
</span>
</div>
</div>
</div>
</div>
\ No newline at end of file
... ...
<div class="ex-reco">
<h1 class="ex-reco-title">精彩推荐</h1>
<div id="ex-reco-list" class="ex-reco-list">
{{# exRecos}}
<div class="ex-reco-item clearfix">
<a class="ex-reco-img" href="{{url}}" target="_blank">
<span class="bg-img" style="background-image:url({{img}})"></span>
</a>
<a href="{{url}}" target="_blank">
<p class="ex-reco-context">{{title}}</p>
</a>
</div>
{{/ exRecos}}
</div>
</div>
<div class="hot">
<h1 class="hot-title">热门标签</h1>
<div class="hot-tag-list">
{{#hotTags}}
<a class="hot-tag" href="{{url}}" target="_blank">
{{tagName}}
</a>
{{/hotTags}}
</div>
</div>
<div class="ads">
{{# ads}}
<a class="ad" href="{{url}}" target="_blank">
<img class="lazy" data-original="{{img}}">
</a>
{{/ ads}}
</div>
\ No newline at end of file
... ...
<div class="floor-ad">
sub tpl my name is {{name}}
</div>
... ...
... ... @@ -15,7 +15,7 @@ const searchApi = require(`${mRoot}/search-api`);
const shop = (shopId, req, res, next, brandInfo) => {
shopId = parseInt(shopId, 10);
list.getShopInfo(shopId, req.user.id).then(shopInfo => {
list.getShopInfo(shopId, req.user.uid).then(shopInfo => {
if (+shopInfo.shopTemplateType === 2) { // 经典模板
let pjax = req.query._pjax;
... ... @@ -83,7 +83,7 @@ exports.new = (req, res, next) => {
* @return {[type]} [description]
*/
exports.brand = (req, res, next) => {
let brandDomain = req.params.brandDomain;
let brandDomain = req.query.domain;
let shopId = req.query.shopId;
let resData = {};
... ... @@ -158,7 +158,7 @@ exports.shopList = (req, res, next) => {
return next();
}
list.getShopListData(req.yoho.channel, req.query).then(result => {
list.getShopListData(req.yoho.channel, req.query, req.user.uid).then(result => {
Object.assign(result, {
page: 'shop',
shopId: shopId
... ...
... ... @@ -9,6 +9,8 @@
const mRoot = '../models';
const sale = require(`${mRoot}/sale`); // sale model
const _ = require('lodash');
/**
* sale 首页
* @param {[type]} req [description]
... ... @@ -16,7 +18,7 @@ const sale = require(`${mRoot}/sale`); // sale 页 model
* @return {[type]} [description]
*/
exports.index = (req, res, next) => {
let channel = req.query.channel || req.cookies._Channel || 'boys';
let channel = req.query.channel || req.yoho.channel;
// 真实数据输出
sale.getSaleIndexData(channel).then(result => {
... ... @@ -41,7 +43,7 @@ exports.discount = (req, res, next) => {
saleType: '3'
}, req.query);
let channel = req.query.channel || req.cookies._Channel || 'boys';
let channel = req.query.channel || req.yoho.channel;
let responseData = {
module: 'product',
... ... @@ -68,7 +70,7 @@ exports.vip = (req, res, next) => {
saleType: '2'
}, req.query);
let channel = req.query.channel || req.cookies._Channel || 'boys';
let channel = req.query.channel || req.yoho.channel;
params.uid = req.user.uid || 0;
... ... @@ -95,7 +97,7 @@ exports.newSale = (req, res, next) => {
order: 's_t_desc'
}, req.query);
let channel = req.query.channel || req.cookies._Channel || 'boys';
let channel = req.query.channel || req.yoho.channel;
sale.getSaleOthersData(params, channel).then((result) => {
res.render('sale/other', Object.assign({
... ... @@ -119,7 +121,7 @@ exports.breakingYards = (req, res, next) => {
saleType: '5'
}, req.query);
let channel = req.query.channel || req.cookies._Channel || 'boys';
let channel = req.query.channel || req.yoho.channel;
let responseData = {
module: 'product',
... ... @@ -150,6 +152,9 @@ exports.special = (req, res, next) => {
return next();
}
_.omit(params, 'specialsale_id');
params.productPool = specialId;
sale.getSaleSpecialData(specialId, params, req.yoho.channel).then(result => {
res.render('sale/special', result);
}).catch(next);
... ...
... ... @@ -208,7 +208,7 @@ const _getBrandDataByProductBaseInfo = (data, additionalData) => {
return {};
}
let brandId = data.brand_info.id;
let brandId = data.brand_info.brand_id;
let bgImg = '';
let logo = '';
let bannerInfo = null;
... ... @@ -373,7 +373,7 @@ const _getFashionTopGoodsStatus = (uid, showStatus, isBeginSale) => {
// dis //失效
// buyNow //是否立即购买
let result = {
getLimitedCode: true,
getLimitedCode: false,
hadLimitedCode: false,
limitedCodeSoldOut: false,
openSoon: false,
... ... @@ -393,17 +393,16 @@ const _getFashionTopGoodsStatus = (uid, showStatus, isBeginSale) => {
result.openSoon = true;
result.hadLimitedCode = false;
}
result.getLimitedCode = true;
break;
case 2: // 开售后,限购码已抢光(用户未领取限购码)
result.buyNow = true;
result.dis = true;
result.limitedCodeSoldOut = true;
result.getLimitedCode = false;
result.hadLimitedCode = false;
break;
case 3: // 开售后,商品已经售罄
result.soldOut = true;
result.getLimitedCode = false;
break;
case 4:// 开售后,立即购买(用户已领取限购码)
result.buyNow = true;
... ... @@ -417,7 +416,6 @@ const _getFashionTopGoodsStatus = (uid, showStatus, isBeginSale) => {
result.openSoon = true;
result.hadLimitedCode = true;
result.limitedCodeSoldOut = true;
result.getLimitedCode = false;
break;
case 6: // 开售前,即将开售(用户已领取限购码)
result.openSoon = true;
... ... @@ -1102,21 +1100,22 @@ const _detailDataPkg = (origin, uid, vipLevel) => {
result.vipPrice = _getVipDataByProductBaseInfo(origin, vipLevel, uid);
}
// 促销活动banner,虚拟商品无促销
// 促销活动banner,虚拟商品无促销
if (propOrigin('attribute') !== 3) {
result.activity = _getActivityDataByProductBaseInfo(promotionData, additionalData);
}
const C_VALUE = {
type: '返有货币',
des: '每件返 ',
rest: '个 有货币'
};
// 有货币
if (!_.includes(['', '0'], propOrigin('yohoCoinNum'))) {
const C_VALUE = {
type: '返有货币',
des: '每件返 ',
rest: '个 有货币'
};
if (propOrigin('yoho_coin_num', '0') !== '0') {
result.activity.push({
type: C_VALUE.type,
des: `${C_VALUE.des}${propOrigin('yoho_coin_num')}${C_VALUE.rest}`
des: `${C_VALUE.des}${propOrigin('yohoCoinNum')}${C_VALUE.rest}`
});
}
... ... @@ -1152,12 +1151,12 @@ const _detailDataPkg = (origin, uid, vipLevel) => {
// 是否收藏
result.isCollect = favoriteData.product;
if (propOrigin('is_limit_buy', false)) {
if (propOrigin('isLimitBuy', false)) {
// 是否开售
let isBeginSale = propOrigin('sale_status', 0) === 1;
let isBeginSale = propOrigin('saleStatus', 0) === 1;
// 限购商品有关的展示状态
let showStatus = propOrigin('show_status', 1);
let showStatus = propOrigin('showStatus', 1);
let fashTopGoods = _getFashionTopGoodsStatus(uid, showStatus, isBeginSale);
... ... @@ -1237,8 +1236,13 @@ const _detailDataPkg = (origin, uid, vipLevel) => {
statGoodsInfo.productId = propOrigin('product_id');
statGoodsInfo.productName = result.name.replace('\'', '’');
statGoodsInfo.brandName = (result.brandName || '').replace('\'', '’');
statGoodsInfo.marketPrice = result.marketPrice;
statGoodsInfo.salePrice = result.salePrice ? result.salePrice : result.marketPrice;
statGoodsInfo.marketPrice = result.marketPrice.replace('¥', ''); // 数字
statGoodsInfo.salePrice = (result.salePrice ? result.salePrice : result.marketPrice).replace('¥', ''); // 数字
statGoodsInfo.imageUrl = 'http:' + result.img.split('?')[0];
statGoodsInfo.productUrl = 'http:' +
helpers.urlFormat(url.parse(propOrigin('product_url')).pathname, null, 'item');
statGoodsInfo.smallSortId = result.smallSortId;
statGoodsInfo.soldOut = soldOut ? 1 : 0;
if (banner.brandId) {
let domainBrand = yield brandService.getBrandByDomainAsync(banner.brandDomain);
... ... @@ -1258,11 +1262,6 @@ const _detailDataPkg = (origin, uid, vipLevel) => {
}
}
statGoodsInfo.imageUrl = 'http:' + result.img.split('?')[0];
statGoodsInfo.productUrl = 'http:' +
helpers.urlFormat(url.parse(propOrigin('product_url')).pathname, null, 'item');
statGoodsInfo.smallSortId = result.smallSortId;
statGoodsInfo.soldOut = soldOut ? 1 : 0;
// 获取商品尺寸相关
let sizeInfo = _getSizeInfo(result, result.maxSortId, additionalData);
... ...
... ... @@ -73,7 +73,7 @@ const getListData = (params, channel) => {
];
// 搜索分类介绍和广告
if (params.msort && params.misort) {
if (params.msort && params.misort && !isNaN(params.misort)) {
let IntroParams = {
max_sort_id: params.msort,
middle_sort_id: params.misort,
... ... @@ -106,19 +106,27 @@ const getListData = (params, channel) => {
finalResult.list = Object.assign(
searchHandler.handlePathNavData(result[1].data.sort, params, 'sort', channel), {
leftContent: searchHandler.handleSortData(result[1].data.sort, dps)
leftContent: searchHandler.handleSortData(result[1].data.sort, dps, params)
});
}
// 获取商品数据和顶部筛选条件
if (result[2].code === 200) {
let filters = Object.assign(searchHandler.handleFilterDataAll(result[2].data, params),
finalResult.list.leftContent.sort);
filters.checkedConditions.conditions = _.concat(filters.checkedConditions.conditions,
finalResult.list.leftContent.checked);
Object.assign(finalResult.list, {
filters: searchHandler.handleFilterDataAll(result[2].data, params),
filters: filters,
opts: searchHandler.handleOptsData(params, result[2].data.total, result[2].data.filter),
totalCount: result[2].data.total,
footPager: searchHandler.handlePagerData(result[2].data.total, params),
goods: productProcess.processProductList(result[2].data.product_list,
Object.assign({showDiscount: false}, params)),
Object.assign({showDiscount: false}, params, {
from: {type: 'list', params: params}
})),
hasNextPage: searchHandler.handleNextPage(params, result[2].data.total),
// 最近浏览记录
... ... @@ -182,19 +190,26 @@ const getListNewData = (params, channel) => {
if (result[1].code === 200) {
finalResult.list = Object.assign(
searchHandler.handlePathNavData(result[1].data.sort, params, 'new', channel), {
leftContent: searchHandler.handleSortData(result[1].data.sort, dps)
leftContent: searchHandler.handleSortData(result[1].data.sort, dps, params)
});
}
// 获取商品数据和顶部筛选条件
if (result[2].code === 200) {
let filters = Object.assign(searchHandler.handleFilterDataAll(result[2].data, params),
finalResult.list.leftContent.sort);
filters.checkedConditions.conditions = _.concat(filters.checkedConditions.conditions,
finalResult.list.leftContent.checked);
Object.assign(finalResult.list, {
filters: searchHandler.handleFilterDataAll(result[2].data, params),
filters: filters,
opts: searchHandler.handleOptsData(params, result[2].data.total, result[2].data.filter),
totalCount: result[2].data.total,
footPager: searchHandler.handlePagerData(result[2].data.total, params),
goods: productProcess.processProductList(result[2].data.product_list,
Object.assign({showDiscount: false, showNew: false}, params)),
Object.assign({showDiscount: false, showNew: false,
from: {type: 'listNew', params: params}}, params)),
hasNextPage: searchHandler.handleNextPage(params, result[2].data.total),
// 最近浏览记录
... ... @@ -265,7 +280,7 @@ const getBrandData = (params, extra, channel) => {
let apiMethod = [
headerModel.requestHeaderData(channel),
searchApi.getSortList(queryBase),
searchApi.getProductList(Object.assign({order: order}, searchParams, queryBase))
searchApi.getProductList(Object.assign(searchParams, {order: order}, queryBase))
];
... ... @@ -292,28 +307,34 @@ const getBrandData = (params, extra, channel) => {
});
Object.assign(finalResult.brand, {
leftContent: searchHandler.handleSortData(result[1].data.sort, dps)
leftContent: searchHandler.handleSortData(result[1].data.sort, dps, params)
}, searchHandler.handlePathNavData(extra, params, 'brand', channel));
}
// 获取商品数据和顶部筛选条件
if (result[2].code === 200) {
let filters = Object.assign(searchHandler.handleFilterDataAll(result[2].data, params),
finalResult.brand.leftContent.sort);
filters.checkedConditions.conditions = _.concat(filters.checkedConditions.conditions,
finalResult.brand.leftContent.checked);
Object.assign(finalResult.brand, {
filters: searchHandler.handleFilterDataAll(result[2].data, params),
filters: filters,
opts: searchHandler.handleOptsData(params, result[2].data.total, result[2].data.filter),
totalCount: result[2].data.total,
footPager: searchHandler.handlePagerData(result[2].data.total, params),
goods: productProcess.processProductList(result[2].data.product_list,
Object.assign({showDiscount: false}, params)),
Object.assign({showDiscount: false, from: {type: 'brand', params: params}}, params)),
hasNextPage: searchHandler.handleNextPage(params, result[2].data.total),
// 最近浏览记录
latestWalk: 7
});
}
// 品牌页不显示品牌筛选项
delete finalResult.brand.filters.brand;
// 品牌页不显示品牌筛选项
_.unset(finalResult, 'brand.filters.brand');
}
finalResult.criteo = {skn: searchHandler.getCriteo(_.get(finalResult.brand, 'goods'))};
... ... @@ -417,7 +438,7 @@ const getShopAbout = (shopId, uid, channel) => {
if (result[1].code === 200) {
let data = result[1].data || {},
decorator = shopHandler.getShopDecorator(data, {}, shopId);
decorator = shopHandler.getShopDecorator(data, {}, shopId, true);
Object.assign(decorator.shopTopBannerBase, {
shopId: shopId,
... ... @@ -637,7 +658,8 @@ const getShopData = (shopId, channel, params, shopInfo) => {
finalResult.leftContent = searchHandler.handleSortData(groupSort, params);
if (finalResult.allGoods) {
Object.assign(finalResult.allGoods, searchHandler.setShopSort(groupSort, params));
Object.assign(finalResult.allGoods, searchHandler.setShopSort(groupSort, Object.assign({},
params, {page: 1})));
}
}
... ... @@ -652,7 +674,7 @@ const getShopData = (shopId, channel, params, shopInfo) => {
for (let i = 0; i < 3; i++) {
trendList.push({
href: articleList[i].url,
href: helpers.urlFormat(`/${articleList[i].id}.html`, '', 'guang'),
src: helpers.getForceSourceUrl(articleList[i].src) +
'?imageView/1/w/{width}/h/{height}',
mainTitle: articleList[i].title,
... ... @@ -712,7 +734,8 @@ const getShopGoodsData = (shopId, channel, params) => {
if (subRes.code === 200) {
let groupSort = _.get(subRes, 'data.sort', []);
Object.assign(resData, searchHandler.setShopSort(groupSort, params));
Object.assign(resData, searchHandler.setShopSort(groupSort, Object.assign(params,
{page: 1})));
}
return resData;
... ... @@ -794,6 +817,9 @@ const getShopListData = (channel, params, uid) => {
}),
footPager: {tip: tip}
});
_.set(finalResult, 'filters.checkedConditions.clearUrl',
`?navBar=${params.navBar}&shopId=${params.shopId}`);
} else {
finalResult.searchEmpty = true;
... ... @@ -886,6 +912,11 @@ const getBaseShopData = (params, extra, channel, shopId) => {
});
}
// 临时删除seo信息
_.unset(resData, 'title');
_.unset(resData, 'keywords');
_.unset(resData, 'description');
return resData;
});
};
... ...
... ... @@ -63,14 +63,14 @@ exports.getSalebreakingYardsSortList = (params) => {
* @return {[type]} [description]
*/
exports.getSaleActivityList = (params, channel) => {
let tempChannel = _.isEmpty(channel) ? 'boys' : channel;
let tempChannel = yhChannel[channel] || yhChannel.boys;
return api.get('', {
id: params.id || null,
method: 'app.activity.get',
sort: '2',
plateform: '1',
yh_channel: yhChannel[tempChannel].channel
yh_channel: tempChannel.channel
});
};
... ...
... ... @@ -379,7 +379,8 @@ exports.getSaleDiscountData = (params, channel) => {
// 处理分页等筛选信息
if (subResult[0].code === 200) {
Object.assign(finalResult, {
leftContent: publicHandler.handleSaleSortData(subResult[0].data.filter.group_sort, params, 'discount'),
leftContent: publicHandler.handleSaleSortData(subResult[0].data.filter.group_sort,
params, 'discount'),
saleList: {
footPager: publicHandler.handlePagerData(subResult[0].data.total, params),
opts: publicHandler.handleSaleOptsData(params, subResult[0].data.total, 'default')
... ... @@ -528,7 +529,7 @@ exports.getSaleSpecialData = (id, params, channel) => {
limit: limit,
attribute_not: 2
});
let banner = JSON.parse(data.banner_img) || [];
let banner = data.banner_img ? JSON.parse(data.banner_img) : [];
Object.assign(resData, {
mainBanner: {
... ... @@ -580,7 +581,8 @@ exports.getSaleSpecialData = (id, params, channel) => {
Object.assign(resData, {
filters: searchHandler.handleFilterDataAll(_.get(result[2], 'data', {}), params),
opts: searchHandler.handleOptsData(params, tip.total),
goods: productProcess.processProductList(_.get(result[2], 'data.product_list', [])),
goods: productProcess.processProductList(_.get(result[2], 'data.product_list', []),
{from: {type: 'saleSpecial', params: params}}),
footPager: {tip: tip}
});
... ...
... ... @@ -22,9 +22,6 @@ const getSortByConditionAsync = (condition) => {
return api.get('sortgroup.json', condition);
};
// 获取list页广告
const adsUrl = '/shops/api/v1/ads/getList';
// 判断用户是否收藏品牌
const isFavoriteBrandUrl = '/shops/service/v1/favorite/getUidBrandFav';
... ... @@ -175,7 +172,12 @@ const getSortIntro = (params) => {
* @return
*/
const getSortAds = (params) => {
return serviceApi.get(adsUrl, params);
let finalParams = {
method: 'app.ads.list'
};
Object.assign(finalParams, params);
return yohoApi.get('', finalParams);
};
/**
... ...
... ... @@ -39,7 +39,7 @@ const handleFilterUrl = (originParam, newParam, delParam) => {
delete tempOriginParam.uid;
_.forEach(tempOriginParam, function(value, key) {
if (!delParam[key]) {
if (!delParam[key] && value) {
dest += `${key}=${value}&`;
}
});
... ... @@ -311,7 +311,7 @@ exports.handleOptsData = (params, total, extra) => {
switch (i) {
case 0:
opt.href = handleFilterUrl(params, {order: ''}, {page: true});
opt.href = handleFilterUrl(params, {}, {page: true, order: true});
if (extra === 'discont') { // 如果是折扣专场
opt.name = '全部';
if (_.isEmpty(params.order) || params.order === 's_t_desc') {
... ... @@ -465,8 +465,12 @@ exports.handleOptsData = (params, total, extra) => {
* @param extra 可以任意传值用来处理特殊情况
* @returns {{}}
*/
exports.handleSortData = (origin, params) => {
let leftContent = {};
exports.handleSortData = (origin, params, originParams) => {
let leftContent = {
sort: {misort: []},
checked: []
};
let list = [],
allCount = 0;
... ... @@ -477,8 +481,6 @@ exports.handleSortData = (origin, params) => {
href: handleFilterUrl(params, {}, {msort: true, misort: true})
}];
//
_.forEach(origin, value => {
let category = {
name: value.sort_name,
... ... @@ -511,6 +513,25 @@ exports.handleSortData = (origin, params) => {
category.active = true;
}
if (subValue.sort_id === params.misort && subValue.sub && subValue.sub.length > 2) {
_.forEach(subValue.sub, smallSort => {
leftContent.sort.misort.push({
id: smallSort.sort_id,
name: smallSort.sort_name,
checked: smallSort.sort_id === _.get(originParams, 'sort'),
href: handleFilterUrl(originParams, {sort: smallSort.sort_id})
});
if (smallSort.sort_id === _.get(originParams, 'sort')) {
leftContent.checked.push({
name: smallSort.sort_name,
href: handleFilterUrl(originParams, {sort: ''})
});
}
});
}
});
list.push(category);
... ... @@ -582,6 +603,9 @@ exports.handleFilterData = (origin, params, total) => {
if (params.price === key) {
priceRangechecked = true;
}
if (_.isString(value)) {
value = _.replace(value, '¥', '¥');
}
let price = {
checked: params.price === key,
href: handleFilterUrl(params, {price: key}),
... ...
... ... @@ -25,7 +25,7 @@ exports.getSearchData = (params, channel) => {
// 调用接口
let apiMethod = [
headerModel.requestHeaderData(channel),
searchApi.getSortList(Object.assign({}, searchParams, {msort: '', misort: ''})),
searchApi.getSortList(Object.assign({}, searchParams, {msort: '', misort: '', sort: ''})),
searchApi.getProductList(searchParams),
searchApi.getShopList(params)
];
... ... @@ -54,21 +54,28 @@ exports.getSearchData = (params, channel) => {
});
finalResult.search = {
leftContent: searchHandler.handleSortData(result[1].data.sort, dps)
leftContent: searchHandler.handleSortData(result[1].data.sort, dps, params)
};
}
// 获取商品数据和顶部筛选条件
if (result[2].code === 200) {
let filters = Object.assign(searchHandler.handleFilterDataAll(result[2].data, params),
finalResult.search.leftContent.sort);
filters.checkedConditions.conditions = _.concat(filters.checkedConditions.conditions,
finalResult.search.leftContent.checked);
Object.assign(finalResult.search,
searchHandler.handlePathNavData({total: result[2].data.total }, params, 'search', channel),
{
filters: searchHandler.handleFilterDataAll(result[2].data, params),
filters: filters,
opts: searchHandler.handleOptsData(params, result[2].data.total, result[2].data.filter),
totalCount: result[2].data.total,
footPager: searchHandler.handlePagerData(result[2].data.total, params),
goods: productProcess.processProductList(result[2].data.product_list,
Object.assign({showDiscount: false}, params)),
Object.assign({showDiscount: false, from: {type: 'search', params: params}}, params)),
latestWalk: 6,
hasNextPage: searchHandler.handleNextPage(params, result[2].data.total),
shopEntry: result[3]
... ...
... ... @@ -77,8 +77,8 @@ router.get('/list/index', list.index);
router.get('/list/new', list.new);
// 品牌页
router.get('/brand/:brandDomain', list.brand);
router.get('/about/:brandDomain', list.brandAbout);
router.get('/index/brand', list.brand);
router.get('/index/about', list.brandAbout);
router.get('/shoplist', list.shopList); // 店铺列表页
router.post('/shop/togglecollect', favorite.collectShop); // 店铺收藏
... ...
... ... @@ -16,8 +16,8 @@ module.exports = {
siteUrl: 'http://www.yohobuy.com',
domains: {
favApi: 'http://192.168.102.31:8092/brower',
api: 'http://api-test1.yohops.com:9999/',
service: 'http://service-test1.yohops.com:9999/',
api: 'http://api.yoho.cn/',
service: 'http://service.yoho.cn/',
search: 'http://192.168.102.216:8080/yohosearch/'
},
subDomains: {
... ...
... ... @@ -14,4 +14,5 @@ module.exports = app => {
app.use('/product', require('./apps/product')); // 商品相关页面
app.use(require('./apps/passport')); // 登录注册
app.use('/home', require('./apps/home')); // 会员中心
app.use('/guang', require('./apps/guang'));
};
... ...
... ... @@ -7,16 +7,24 @@
module.exports = () => {
return (req, res, next) => {
let searchReg = /^\/product\//;
let searchReg = /^\/product\//,
guangReg = /^\/guang/,
guangDetailReg = /.html$/;
if (req.subdomains.length) {
switch (req.subdomains[0]) {
case 'www': // 主站
case 'new': // 原新版
case 'guang': // 逛
case 'shop': // 商家入驻
case 'item':// 商品详情页
break;
case 'guang': // 逛
if (guangDetailReg.test(req.path)) {
req.url = '/guang/detail' + req.url;
} else if (!guangReg.test(req.path)) {
req.url = '/guang' + req.url;
}
break;
case 'search': // 搜索
if (!searchReg.test(req.path)) {
if (req.path === '/api/suggest') {
... ... @@ -40,9 +48,11 @@ module.exports = () => {
break;
default: // 其它(识别为品牌)
if (!req.path || req.path === '/') {
req.url = `/product/brand/${req.subdomains[0]}`;
req.url = `/product/index/brand?domain=${req.subdomains[0]}`;
req.query.domain = req.subdomains[0];
} else if (req.path === '/about') {
req.url = `/product/about/${req.subdomains[0]}`;
req.url = `/product/index/about?domain=${req.subdomains[0]}`;
req.query.domain = req.subdomains[0];
}
break;
}
... ...
... ... @@ -50,20 +50,6 @@
</div>
{{/if}}
{{#if ageLevel}}
<div class="channel section">
<span class="title">人群:</span>
<div class="attr-content clearfix">
{{#each ageLevel}}
<a class="attr {{#if checked}}checked{{/if}}" href="{{href}}">
{{name}}
</a>
{{/each}}
</div>
</div>
{{/if}}
{{#if sort}}
<div class="sort section">
<span class="title">分类:</span>
... ... @@ -143,6 +129,20 @@
{{> product/filter-brands}}
</script>
{{#if ageLevel}}
<div class="channel section">
<span class="title">人群:</span>
<div class="attr-content clearfix">
{{#each ageLevel}}
<a class="attr {{#if checked}}checked{{/if}}" href="{{href}}">
{{name}}
</a>
{{/each}}
</div>
</div>
{{/if}}
{{#if price}}
<div class="price section">
<span class="title">价格:</span>
... ...
... ... @@ -78,7 +78,7 @@
</p>
<div class="hideList hide">
{{#goods_list}}
<li data-src="{{image images_url 280 374}}" data-url="{{../url}}" data-status="{{status}}"></li>
<li data-src="{{image images_url 280 382}}" data-url="{{../url}}" data-status="{{status}}"></li>
{{/goods_list}}
</div>
</div>
... ...
<span class="share-wrapper share-to pull-left clearfix">
<i class="weibo" data-type="weibo" title="分享到新浪微博"></i>
<i class="weixin" data-type="weixin" title="分享到微信朋友圈"></i>
<i class="tweibo" data-type="tweibo" title="分享到腾讯微博"></i>
<i class="qzone" data-type="qzone" title="分享到QQ空间"></i>
<i class="qq" data-type="qq" title="分享到QQ好友"></i>
<i class="renren" data-type="renren" title="分享到人人"></i>
<i class="douban" data-type="douban" title="分享到豆瓣"></i>
<div class="weixin-share-box"></div>
</span>
<input id="share-img" type="hidden" value="{{shareImg}}">
<input id="share-desc" type="hidden" value="{{shareDesc}}">
<input id="weixin-url" type="hidden" value="{{weixinUrl}}">
\ No newline at end of file
... ...
{
"name": "yohobuy-node",
"version": "5.0.2",
"version": "5.0.4",
"private": true,
"description": "A New Yohobuy Project With Express",
"repository": {
... ... @@ -37,6 +37,7 @@
"connect-memcached": "^0.2.0",
"cookie-parser": "^1.4.3",
"express": "^4.13.1",
"handlebars": "^4.0.5",
"express-handlebars": "^3.0.0",
"influxdb-winston": "^1.0.1",
"lodash": "^4.13.1",
... ... @@ -53,6 +54,7 @@
"passport-sina": "^0.1.0",
"passport-strategy": "1.x.x",
"passport-weixin": "^0.1.0",
"request-ip": "^1.2.2",
"request-promise": "^3.0.0",
"serve-favicon": "^2.3.0",
"uuid": "^2.0.2",
... ... @@ -103,7 +105,8 @@
"yoho-jquery-lazyload": "^1.9.7",
"yoho-jquery-pjax": "0.0.1",
"yoho-jquery-placeholder": "^2.3.1",
"yoho-jquery-qrcode": "^0.14.0",
"yoho-slider": "0.0.2"
"yoho-slider": "0.0.2",
"yoho-jquery-dotdotdot": "0.0.1",
"yoho-jquery-qrcode": "^0.14.0"
}
}
... ...
*{margin: 0;padding: 0;list-style: none;}
/*
KISSY CSS Reset
理念:1. reset 的目的不是清除浏览器的默认样式,这仅是部分工作。清除和重置是紧密不可分的。
2. reset 的目的不是让默认样式在所有浏览器下一致,而是减少默认样式有可能带来的问题。
3. reset 期望提供一套普适通用的基础样式。但没有银弹,推荐根据具体需求,裁剪和修改后再使用。
特色:1. 适应中文;2. 基于最新主流浏览器。
维护:玉伯<lifesinger@gmail.com>, 正淳<ragecarrier@gmail.com>
*/
/** 清除内外边距 **/
body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, /* structural elements 结构元素 */
dl, dt, dd, ul, ol, li, /* list elements 列表元素 */
pre, /* text formatting elements 文本格式元素 */
form, fieldset, legend, button, input, textarea, /* form elements 表单元素 */
th, td /* table elements 表格元素 */ {
margin: 0;
padding: 0;
}
/** 设置默认字体 **/
body,
button, input, select, textarea /* for ie */ {
font: 12px/1.5 tahoma, arial, \5b8b\4f53, sans-serif;
}
h1, h2, h3, h4, h5, h6 { font-size: 100%; }
address, cite, dfn, em, var { font-style: normal; } /* 将斜体扶正 */
code, kbd, pre, samp { font-family: courier new, courier, monospace; } /* 统一等宽字体 */
small { font-size: 12px; } /* 小于 12px 的中文很难阅读,让 small 正常化 */
/** 重置列表元素 **/
ul, ol { list-style: none; }
/** 重置文本格式元素 **/
a { text-decoration: none; }
a:hover { text-decoration: underline; }
/** 重置表单元素 **/
legend { color: #000; } /* for ie6 */
fieldset, img { border: 0; } /* img 搭车:让链接里的 img 无边框 */
button, input, select, textarea { font-size: 100%; } /* 使得表单元素在 ie 下能继承字体大小 */
/* 注:optgroup 无法扶正 */
/** 重置表格元素 **/
table { border-collapse: collapse; border-spacing: 0; }
/* 清除浮动 */
.ks-clear:after, .clear:after {
content: '\20';
display: block;
height: 0;
clear: both;
}
.ks-clear, .clear {
*zoom: 1;
}
.main {padding: 30px 100px;}
.main h1{font-size:36px; color:#333; text-align:left;margin-bottom:30px; border-bottom: 1px solid #eee;}
.helps{margin-top:40px;}
.helps pre{
padding:20px;
margin:10px 0;
border:solid 1px #e7e1cd;
background-color: #fffdef;
overflow: auto;
}
.icon_lists li{
float:left;
width: 100px;
height:180px;
text-align: center;
}
.icon_lists .icon{
font-size: 42px;
line-height: 100px;
margin: 10px 0;
color:#333;
-webkit-transition: font-size 0.25s ease-out 0s;
-moz-transition: font-size 0.25s ease-out 0s;
transition: font-size 0.25s ease-out 0s;
}
.icon_lists .icon:hover{
font-size: 100px;
}
... ...
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>IconFont</title>
<link rel="stylesheet" href="demo.css">
<link rel="stylesheet" href="iconfont.css">
</head>
<body>
<div class="main">
<h1>IconFont 图标</h1>
<ul class="icon_lists clear">
<li>
<i class="icon iconfont">&#xe624;</i>
<div class="name">评论</div>
<div class="code">&amp;#xe624;</div>
<div class="fontclass">.pinglun</div>
</li>
<li>
<i class="icon iconfont">&#xe618;</i>
<div class="name">左三角</div>
<div class="code">&amp;#xe618;</div>
<div class="fontclass">.zuosanjiao</div>
</li>
<li>
<i class="icon iconfont">&#xe619;</i>
<div class="name">右三角</div>
<div class="code">&amp;#xe619;</div>
<div class="fontclass">.yousanjiao</div>
</li>
<li>
<i class="icon iconfont">&#xe60b;</i>
<div class="name">向下</div>
<div class="code">&amp;#xe60b;</div>
<div class="fontclass">.chevron-down</div>
</li>
<li>
<i class="icon iconfont">&#xe60c;</i>
<div class="name">向右</div>
<div class="code">&amp;#xe60c;</div>
<div class="fontclass">.chevron-right</div>
</li>
<li>
<i class="icon iconfont">&#xe605;</i>
<div class="name">对号</div>
<div class="code">&amp;#xe605;</div>
<div class="fontclass">.duihao</div>
</li>
<li>
<i class="icon iconfont">&#xe61b;</i>
<div class="name">购物车</div>
<div class="code">&amp;#xe61b;</div>
<div class="fontclass">.gouwuche</div>
</li>
<li>
<i class="icon iconfont">&#xe60d;</i>
<div class="name"></div>
<div class="code">&amp;#xe60d;</div>
<div class="fontclass">.cha</div>
</li>
<li>
<i class="icon iconfont">&#xe61c;</i>
<div class="name">forbid</div>
<div class="code">&amp;#xe61c;</div>
<div class="fontclass">.forbid</div>
</li>
<li>
<i class="icon iconfont">&#xe60e;</i>
<div class="name">left</div>
<div class="code">&amp;#xe60e;</div>
<div class="fontclass">.left</div>
</li>
<li>
<i class="icon iconfont">&#xe614;</i>
<div class="name">sort</div>
<div class="code">&amp;#xe614;</div>
<div class="fontclass">.sort</div>
</li>
<li>
<i class="icon iconfont">&#xe625;</i>
<div class="name">时间</div>
<div class="code">&amp;#xe625;</div>
<div class="fontclass">.iconsj</div>
</li>
<li>
<i class="icon iconfont">&#xe60f;</i>
<div class="name">search</div>
<div class="code">&amp;#xe60f;</div>
<div class="fontclass">.search</div>
</li>
<li>
<i class="icon iconfont">&#xe615;</i>
<div class="name">三角2</div>
<div class="code">&amp;#xe615;</div>
<div class="fontclass">.sanjiao2</div>
</li>
<li>
<i class="icon iconfont">&#xe610;</i>
<div class="name">三角1</div>
<div class="code">&amp;#xe610;</div>
<div class="fontclass">.sanjiao1</div>
</li>
<li>
<i class="icon iconfont">&#xe608;</i>
<div class="name">向右</div>
<div class="code">&amp;#xe608;</div>
<div class="fontclass">.xiangyou</div>
</li>
<li>
<i class="icon iconfont">&#xe609;</i>
<div class="name">向左</div>
<div class="code">&amp;#xe609;</div>
<div class="fontclass">.xiangzuo</div>
</li>
<li>
<i class="icon iconfont">&#xe620;</i>
<div class="name">问号</div>
<div class="code">&amp;#xe620;</div>
<div class="fontclass">.wenhao</div>
</li>
<li>
<i class="icon iconfont">&#xe61d;</i>
<div class="name">向下</div>
<div class="code">&amp;#xe61d;</div>
<div class="fontclass">.xiangxia</div>
</li>
<li>
<i class="icon iconfont">&#xe621;</i>
<div class="name">电话</div>
<div class="code">&amp;#xe621;</div>
<div class="fontclass">.dianhua</div>
</li>
<li>
<i class="icon iconfont">&#xe60a;</i>
<div class="name">time</div>
<div class="code">&amp;#xe60a;</div>
<div class="fontclass">.time</div>
</li>
<li>
<i class="icon iconfont">&#xe626;</i>
<div class="name"></div>
<div class="code">&amp;#xe626;</div>
<div class="fontclass">.zan</div>
</li>
<li>
<i class="icon iconfont">&#xe607;</i>
<div class="name">up</div>
<div class="code">&amp;#xe607;</div>
<div class="fontclass">.up</div>
</li>
<li>
<i class="icon iconfont">&#xe611;</i>
<div class="name">Heart</div>
<div class="code">&amp;#xe611;</div>
<div class="fontclass">.heart</div>
</li>
<li>
<i class="icon iconfont">&#xe616;</i>
<div class="name">login_check_button1</div>
<div class="code">&amp;#xe616;</div>
<div class="fontclass">.logincheckbutton1</div>
</li>
<li>
<i class="icon iconfont">&#xe601;</i>
<div class="name">mail</div>
<div class="code">&amp;#xe601;</div>
<div class="fontclass">.aaa</div>
</li>
<li>
<i class="icon iconfont">&#xe61e;</i>
<div class="name">评论</div>
<div class="code">&amp;#xe61e;</div>
<div class="fontclass">.pinglun1</div>
</li>
<li>
<i class="icon iconfont">&#xe622;</i>
<div class="name">正确</div>
<div class="code">&amp;#xe622;</div>
<div class="fontclass">.zhengque</div>
</li>
<li>
<i class="icon iconfont">&#xe606;</i>
<div class="name">circle</div>
<div class="code">&amp;#xe606;</div>
<div class="fontclass">.circle</div>
</li>
<li>
<i class="icon iconfont">&#xe627;</i>
<div class="name">eye</div>
<div class="code">&amp;#xe627;</div>
<div class="fontclass">.eye</div>
</li>
<li>
<i class="icon iconfont">&#xe61f;</i>
<div class="name">03-叹号</div>
<div class="code">&amp;#xe61f;</div>
<div class="fontclass">.03tanhao</div>
</li>
<li>
<i class="icon iconfont">&#xe61a;</i>
<div class="name">home</div>
<div class="code">&amp;#xe61a;</div>
<div class="fontclass">.home</div>
</li>
<li>
<i class="icon iconfont">&#xe600;</i>
<div class="name">shopping-card</div>
<div class="code">&amp;#xe600;</div>
<div class="fontclass">.shoppingcard</div>
</li>
<li>
<i class="icon iconfont">&#xe617;</i>
<div class="name">checkbox-checked</div>
<div class="code">&amp;#xe617;</div>
<div class="fontclass">.checkboxchecked</div>
</li>
<li>
<i class="icon iconfont">&#xe623;</i>
<div class="name">五角星</div>
<div class="code">&amp;#xe623;</div>
<div class="fontclass">.wujiaoxing</div>
</li>
<li>
<i class="icon iconfont">&#xe612;</i>
<div class="name">select</div>
<div class="code">&amp;#xe612;</div>
<div class="fontclass">.zhengchang</div>
</li>
<li>
<i class="icon iconfont">&#xe613;</i>
<div class="name">selected</div>
<div class="code">&amp;#xe613;</div>
<div class="fontclass">.weibiaoti7</div>
</li>
<li>
<i class="icon iconfont">&#xe602;</i>
<div class="name">sya</div>
<div class="code">&amp;#xe602;</div>
<div class="fontclass">.say1</div>
</li>
<li>
<i class="icon iconfont">&#xe603;</i>
<div class="name">7days</div>
<div class="code">&amp;#xe603;</div>
<div class="fontclass">.7t11</div>
</li>
<li>
<i class="icon iconfont">&#xe604;</i>
<div class="name">zheng</div>
<div class="code">&amp;#xe604;</div>
<div class="fontclass">.z</div>
</li>
</ul>
<div class="helps">
第一步:使用font-face声明字体
<pre>
@font-face {font-family: 'iconfont';
src: url('iconfont.eot'); /* IE9*/
src: url('iconfont.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('iconfont.woff') format('woff'), /* chrome、firefox */
url('iconfont.ttf') format('truetype'), /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/
url('iconfont.svg#iconfont') format('svg'); /* iOS 4.1- */
}
</pre>
第二步:定义使用iconfont的样式
<pre>
.iconfont{
font-family:"iconfont" !important;
font-size:16px;font-style:normal;
-webkit-font-smoothing: antialiased;
-webkit-text-stroke-width: 0.2px;
-moz-osx-font-smoothing: grayscale;}
</pre>
第三步:挑选相应图标并获取字体编码,应用于页面
<pre>
&lt;i class="iconfont"&gt;&amp;#x33;&lt;/i&gt;
</pre>
</div>
</div>
</body>
</html>
... ...
@font-face {font-family: "iconfont";
src: url('iconfont.eot?t=1473148446'); /* IE9*/
src: url('iconfont.eot?t=1473148446#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('iconfont.woff?t=1473148446') format('woff'), /* chrome, firefox */
url('iconfont.ttf?t=1473148446') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
url('iconfont.svg?t=1473148446#iconfont') format('svg'); /* iOS 4.1- */
}
.iconfont {
font-family:"iconfont" !important;
font-size:16px;
font-style:normal;
-webkit-font-smoothing: antialiased;
-webkit-text-stroke-width: 0.2px;
-moz-osx-font-smoothing: grayscale;
}
.icon-pinglun:before { content: "\e624"; }
.icon-zuosanjiao:before { content: "\e618"; }
.icon-yousanjiao:before { content: "\e619"; }
.icon-chevron-down:before { content: "\e60b"; }
.icon-chevron-right:before { content: "\e60c"; }
.icon-duihao:before { content: "\e605"; }
.icon-gouwuche:before { content: "\e61b"; }
.icon-cha:before { content: "\e60d"; }
.icon-forbid:before { content: "\e61c"; }
.icon-left:before { content: "\e60e"; }
.icon-sort:before { content: "\e614"; }
.icon-iconsj:before { content: "\e625"; }
.icon-search:before { content: "\e60f"; }
.icon-sanjiao2:before { content: "\e615"; }
.icon-sanjiao1:before { content: "\e610"; }
.icon-xiangyou:before { content: "\e608"; }
.icon-xiangzuo:before { content: "\e609"; }
.icon-wenhao:before { content: "\e620"; }
.icon-xiangxia:before { content: "\e61d"; }
.icon-dianhua:before { content: "\e621"; }
.icon-time:before { content: "\e60a"; }
.icon-zan:before { content: "\e626"; }
.icon-up:before { content: "\e607"; }
.icon-heart:before { content: "\e611"; }
.icon-logincheckbutton1:before { content: "\e616"; }
.icon-aaa:before { content: "\e601"; }
.icon-pinglun1:before { content: "\e61e"; }
.icon-zhengque:before { content: "\e622"; }
.icon-circle:before { content: "\e606"; }
.icon-eye:before { content: "\e627"; }
.icon-03tanhao:before { content: "\e61f"; }
.icon-home:before { content: "\e61a"; }
.icon-shoppingcard:before { content: "\e600"; }
.icon-checkboxchecked:before { content: "\e617"; }
.icon-wujiaoxing:before { content: "\e623"; }
.icon-zhengchang:before { content: "\e612"; }
.icon-weibiaoti7:before { content: "\e613"; }
.icon-say1:before { content: "\e602"; }
.icon-7t11:before { content: "\e603"; }
.icon-z:before { content: "\e604"; }
... ...
No preview for this file type
... ... @@ -2,7 +2,11 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>
<<<<<<< HEAD
Created by FontForge 20120731 at Tue Sep 6 15:54:06 2016
=======
Created by FontForge 20120731 at Wed Sep 21 17:18:20 2016
>>>>>>> remotes/origin/master
By admin
</metadata>
<defs>
... ... @@ -19,7 +23,11 @@ Created by FontForge 20120731 at Wed Sep 21 17:18:20 2016
bbox="0 -212 1158 896"
underline-thickness="50"
underline-position="-100"
<<<<<<< HEAD
unicode-range="U+0078-E627"
=======
unicode-range="U+0078-E62A"
>>>>>>> remotes/origin/master
/>
<missing-glyph horiz-adv-x="374"
d="M34 0v682h272v-682h-272zM68 34h204v614h-204v-614z" />
... ... @@ -141,6 +149,8 @@ q0 -28 20 -48.5t49 -20.5h137v518h-137q-29 0 -49 -20.5t-20 -48.5zM0 379z" />
<glyph glyph-name="uniE627" unicode="&#xe627;" horiz-adv-x="1025"
d="M512 719q-167 0 -304.5 -89.5t-205.5 -236.5q-4 -9 0 -18q68 -147 205.5 -236.5t304.5 -89.5t304.5 89.5t205.5 236.5q4 9 0 18q-68 147 -205.5 236.5t-304.5 89.5zM512 153q-96 0 -163.5 67.5t-67.5 163.5t67.5 163.5t163.5 67.5t163.5 -67.5t67.5 -163.5t-67.5 -163.5
t-163.5 -67.5zM512 384zM364 384q0 61 43.5 104.5t104.5 43.5t104.5 -43.5t43.5 -104.5t-43.5 -104.5t-104.5 -43.5t-104.5 43.5t-43.5 104.5z" />
<<<<<<< HEAD
=======
<glyph glyph-name="uniE628" unicode="&#xe628;"
d="M512 886q-102 0 -195 -39.5t-160.5 -107t-107 -160.5t-39.5 -195t39.5 -195t107 -160.5t160.5 -107t195 -39.5t195 39.5t160.5 107t107 160.5t39.5 195t-39.5 195t-107 160.5t-160.5 107t-195 39.5zM521 -15q-34 0 -58.5 24t-24.5 58.5t24.5 58.5t58.5 24t58 -24t24 -58
q1 -34 -23.5 -58.5t-58.5 -24.5zM738 477q-17 -34 -67 -83q-45 -43 -60 -61q-12 -16 -17 -35q-6 -22 -6 -61l1 -31h-142v30q0 56 9 90q11 38 30 64q17 23 62 71q43 44 52 60q8 13 8 44q0 28 -20 51q-20 21 -61 21q-29 0 -48.5 -9.5t-28.5 -27.5t-12.5 -36t-3.5 -43v-30h-142
... ... @@ -150,5 +160,6 @@ d="M511 833q-91 0 -174 -36t-143 -96t-95.5 -143t-35.5 -174t35.5 -174t95.5 -143t14
t-34 14t-14 34t14 34l192 191l-192 192q-14 14 -14 34t14 34t34 14t34 -14l192 -192l192 192q14 14 33.5 14t34 -14t14.5 -34t-15 -34l-191 -192z" />
<glyph glyph-name="uniE62A" unicode="&#xe62a;"
d="M799 456l127 127v313h-830v-609l421 -413l409 404v181l-414 -401l-288 284v426h575v-312zM671 518l-107 22l-53 100l-52 -100l-108 -22l75 -83l-14 -114l99 49l99 -49l-14 114z" />
>>>>>>> remotes/origin/master
</font>
</defs></svg>
... ...
No preview for this file type
No preview for this file type
/**
* 分享
* @author: xuqi<qi.xu@yoho.cn>
* @date: 2016/3/1
*/
var $ = require('yoho-jquery');
function shareBase(options) {
var openUrl = '';
var defOption = {
title: '',
url: window.location.href,
weixinUrl: '',
image: '',
desc: '',
channel: ''
};
var shareChannels = ['weibo', 'tweibo', 'qzone', 'renren', 'qq', 'douban', 'weixin'];
var sharebox;
var shareCon = '<em><i></i></em>';
defOption = $.extend(defOption, options);
if (defOption.image && defOption.image.substr(0, 2) === '//') {
defOption.image = 'http:' + defOption.image;
}
if (defOption.weixinUrl && defOption.weixinUrl.substr(0, 2) === '//') {
defOption.weixinUrl = 'http:' + defOption.weixinUrl;
}
if (defOption.url && defOption.url.substr(0, 2) === '//') {
defOption.url = 'http:' + defOption.url;
}
if ($.inArray(defOption.channel, shareChannels) === -1) {
alert('不存在的分享平台!');
return false;
}
switch (defOption.channel) {
case 'weibo':
openUrl = 'http://service.weibo.com/share/share.php?url=' + defOption.url + '&title=' +
defOption.title + '&appkey=3739328910&searchPic=true&pic=' + defOption.image;
break;
case 'tweibo':
openUrl = 'http://share.v.t.qq.com/index.php?c=share&a=index&url=' + defOption.url + '&title=' +
defOption.title + '&appkey=c0af9c29e0900813028c2ccb42021792&pic=' + defOption.image;
break;
case 'qzone':
openUrl = 'http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=' + defOption.url + '&title=' +
defOption.title + '&desc=&summary=' + defOption.desc + '&site=YOHO!BUY 有货&pics=' + defOption.image;
break;
case 'renren':
openUrl = 'http://widget.renren.com/dialog/share?resourceUrl=' + defOption.url + '&srcUrl=' +
defOption.url + '&desc=' + defOption.desc + '&title=' + defOption.title + '&description=' +
defOption.desc + '&pic=' + defOption.image;
break;
case 'qq':
openUrl = 'http://connect.qq.com/widget/shareqq/index.html?url=' + defOption.url + '&desc=' +
defOption.desc + '&title=' + defOption.title.replace('%', '') + '&desc=&summary=' +
defOption.desc + '&site=YOHO!BUY 有货&pics=' + defOption.image;
break;
case 'weixin':
openUrl = 'http://s.jiathis.com/qrcode.php?url=' + defOption.weixinUrl + '&desc=' +
defOption.desc + '&title=' + defOption.title + '&description=' +
defOption.desc + '&pic=' + defOption.image;
break;
case 'douban':
openUrl = '//www.douban.com/share/service?href=' + defOption.url + '&text=' +
defOption.desc + '&image=' + defOption.image + '&title=' + defOption.title + '&comment=';
break;
}
if (defOption.channel === 'weixin') {
if (!defOption.self) {
return;
}
sharebox = defOption.self.closest('.share-to').find('.weixin-share-box');
if (sharebox.length > 0) {
shareCon += '<div class="con"><h2>分享到微信朋友圈</h2><p class="pic">' +
'<img src="' + openUrl + '" /></p><p class="w">打开微信,点击底部得“发现”,使用<br/>“扫一扫“即可将网页分享到我的朋友圈。</p>' +
'<a href="javascript:void(0)" class="close">x</a></div>';
sharebox.find('div').length > 0 ? sharebox.show() : sharebox.html(shareCon).show();
sharebox.find('.close').click(function() {
$(this).closest('.weixin-share-box').hide();
});
}
} else {
window.open(encodeURI(openUrl));
}
}
function share(channel, self) {
var title = document.title.replace(/(^\s*)|(\s*$)/g, '');
var desc = $('#share-desc').val();
var image = $('#share-img').val();
var weixinUrl = $('#weixin-url').val();
if (channel === 'weibo' || channel === 'tqq') {
shareBase({
channel: channel,
title: title,
image: image
});
} else {
shareBase({
channel: channel,
title: title,
desc: desc,
image: image,
self: self,
weixinUrl: weixinUrl
});
}
}
$('.share-wrapper').on('click', 'i', function() {
var $el = $(this),
type = $el.data('type'),
$weixinShareBox = $('.weixin-share-box');
if (type === 'weixin') {
share(type, $el);
} else {
$weixinShareBox.hide();
share(type);
}
});
... ...
/**
* 动态获取页面数据
* @author liuchuanyang
* @date 2016/10/09
*/
var $ = require('yoho-jquery');
function getDynamicById(id) {
'use strict';
var param = {
id: id
};
// //guang.yohobuy.com/guang/info/detailData
return $.getJSON('/guang/info/detailData', param);
}
function renderData(data) {
'use strict';
var $favor = $('#collect-btn'),
$praise = $('#prise-btn');
if (data && data.code === 200 && data.data) {
if (data.data.isFavor === 'Y') {
$favor.addClass('collected');
} else {
$favor.removeClass('collected');
}
if (data.data.isPraise === 'Y') {
$praise.addClass('liked');
} else {
$praise.removeClass('liked');
}
$praise.find('.like-num').text(data.data.praiseNum || 0);
$('.detail-body .article-click em').text(data.data.browseNum || 0);
}
}
function refreshData() {
'use strict';
var id = $('.detail-body').attr('data-id');
getDynamicById(id).done(renderData);
}
refreshData();
... ...
/**
* 逛详情页
* @author: liuyue<yue.liu@yoho.cn>
* @date: 2015/12/16
*/
var $ = require('yoho-jquery'),
lazyLoad = require('yoho-jquery-lazyload'),
$commentArea = $('#comment-area'),
articleId = $('.detail-body').data('id');
var $commentList = $commentArea.find('.comments-wrap'),
$commentNum = $('#article-comment > .comment-num'),
commenting = false, // 评论请求尚未返回变量
locating = false, // 评论页面正在跳转
$commentBtn = $('#comment-btn'),
MAX_COMMENTS_WORDS = 100,
$wordCountTip = $('#word-count-tip');
require('./right-side');
require('./img-blink');
require('../common/share');
require('./detail-dynamic');
// Pjax
require('yoho-jquery-pjax');
lazyLoad({
failure_limit: 50
});
// 点击评论滑到评论区
// $('#article-comment').click(function() {
// $('html, body').animate({
// scrollTop: $commentArea.offset().top - 20
// }, 800);
// });
// 文章点赞与取消点赞
$('#prise-btn').click(function() {
var prising = false,
url,
$this = $(this);
if (prising) {
return;
}
$this.toggleClass('liked');
if ($this.hasClass('liked')) {
// 点赞
url = '/guang/info/praise';
} else {
// 取消点赞
url = '/guang/info/cancelPraise';
}
prising = true;
$.ajax({
type: 'GET',
url: url,
data: {
id: articleId
}
}).then(function(data) {
if (data.code === 200) {
$this.find('.like-num').html(data.data);
}
prising = false;
});
}).bind('mouseenter mouseleave', function() {
$(this).toggleClass('hover');
});
// 文章收藏与取消收藏
$('#collect-btn').click(function() {
var collecting = false,
url,
col,
$this = $(this);
if (collecting) {
return;
}
if ($this.hasClass('collected')) {
// 取消收藏
url = '/guang/info/cancelcollect';
col = 0;
} else {
// 收藏
url = '/guang/info/collect';
col = 1;
}
collecting = true;
$.ajax({
type: 'GET',
url: url,
data: {
id: articleId
}
}).then(function(data) {
var hrefUrl;
switch (data.code) {
case 401:
// 防止从已有col的页面再次进行跳转后出错的情况
if (/\?col=(1|0)/.test(location.href)) {
hrefUrl = location.href.replace(/\?col=(1|0)/, '?col=' + col);
} else {
hrefUrl = location.href + '?col=' + col;
}
location.href = '//www.yohobuy.com/signin.html?refer=' + encodeURI(hrefUrl);
break;
case 400:
// alert(data.message);
break;
case 200:
if (/\?col=(1|0)/.test(location.href)) {
// 如果页面url中含有col,为了防止页面刷新时收藏或者取消收藏会根据col来的问题,进行页面跳转拿掉参数
location.href = location.href.replace(/\?col=(1|0)/, '');
} else {
$this.toggleClass('collected');
}
break;
}
collecting = false;
});
}).bind('mouseenter mouseleave', function() {
$(this).toggleClass('hover');
});
function showComment() {
var commonlist = $('.comments-list').find('li').length;
if (commonlist === 0) {
$('.commnets-resultwrapper').hide();
$('.comments-empty').show();
} else {
$('.commnets-resultwrapper').show();
$('.comments-empty').hide();
}
}
showComment();
// 评论
function comment(id) {
var commentInfo = $('#comment-info').val();
if (commentInfo === '') {
alert('评论不能为空');
return false;
}
commenting = true;
$.ajax({
url: '/guang/info/comment',
data: {
id: id,
comment: commentInfo
},
type: 'post',
success: function(data) {
switch (data.code) {
case 401:
locating = true;
location.href = '//www.yohobuy.com/signin.html?refer=' +
window.escape(location.href + '#comment-info');
break;
case 400:
alert(data.message);
break;
case 200:
if (data.data) {
$commentList.html(data.data.content);
$commentNum.html(data.data.count);
showComment();
// clear comment-text
$('#comment-info').val('').keyup();
}
break;
}
commenting = false;
}
});
}
$commentBtn.click(function(e) {
// 页面正在跳转或者正在AJAX请求时评论无效
if (locating || commenting) {
return false;
}
// 字数不符合要求
if ($('#comment-info').val().length - MAX_COMMENTS_WORDS > 0) {
return;
}
e.preventDefault();
comment(articleId);
});
// comment pager pjax
$(document).pjax('.comment-pager a', '#pjax-container', {
timeout: 5000
});
// 分页后移动到评论框的位置
$(document).on('pjax:end', function() {
showComment();
$('html,body').scrollTop($('#comment-info').offset().top);
// 设置头部评论数
$('#article-comment .comment-num').text($('#comment-area .comment-num').text());
});
$('#comment-info').keyup(function() {
var len = $(this).val().length,
showTxt;
if (len === 0) {
$wordCountTip.html('');
$commentBtn.addClass('disable');
} else {
if (len - MAX_COMMENTS_WORDS <= 0) {
showTxt = '还可以输入' + (MAX_COMMENTS_WORDS - len) + '字';
$commentBtn.removeClass('disable');
} else {
showTxt = '已超过<span class="exceed-count">' + (len - MAX_COMMENTS_WORDS) + '</span>字';
$commentBtn.addClass('disable');
}
}
$wordCountTip.html(showTxt);
});
// init
$('#comment-info').trigger('keyup');
... ...
/**
* 逛首页
* @author: xuqi<qi.xu@yoho.cn>
* @date: 2015/12/15
*/
var $ = require('yoho-jquery');
var msg = require('./msg');
require('yoho-jquery-pjax');
require('../plugins/slider');
require('./img-blink');
require('./right-side');
// page cache下更新点赞状态、点赞数、评论数、阅读数
require('./list-dynamic');
$('#slider').slider(); // 初始化slider
$(document).pjax('.pjax-link, .msg-pager a', '#pjax-container', {
timeout: 2000
});
$(document).on('pjax:end', function() {
msg.dotLazy();
});
... ...
/**
* 图片移入闪动效果JS
* @auhor: xuqi<qi.xu@yoho.cn>
* @date: 2015/7/29
*/
var $ = require('yoho-jquery');
$('.guang-page').on('mouseover', 'a img, a .bg-img', function(e) {
var $el = $(e.target);
// slider中的图片不做此效果
if ($el.closest('.slider').length > 0) {
return;
}
$el.addClass('blink');
setTimeout(function() {
$el.removeClass('blink');
}, 100);
});
... ...
/**
* 动态获取页面数据
* @author liuchuanyang
* @date 2016/10/09
*/
var $ = require('yoho-jquery');
var $msgs = $('#msg-list');
require('../common');
function getDynamicByIds(ids) {
'use strict';
var data = {
ids: ids
};
var qs = window.queryString();
if (qs.query) {
// 标签列表
data.query = qs.query;
} else if (qs.type) {
// 逛首页type
data.type = qs.type;
} else if (!qs.author_id) {
// 非编辑页的情况下,为逛首页默认type=0
data.type = '0';
}
return $.ajax({
type: 'GET',
url: '/guang/info/listData',
data: data
});
}
function renderData(data) {
'use strict';
var i,
it,
$it;
var list;
if (data && data.code === 200 && (list = data.data.artList)) {
for (i = 0; i < list.length; i++) {
it = list[i];
if (it && it.articleId) {
$it = $('.msg-content[data-id=' + it.articleId + ']', $msgs);
// 浏览数目
$it.find('.page-view em').text(it.views_num);
// 点赞状态
if (it.isPraise === 'Y') {
$it.find('.like-icon').addClass('liked');
} else {
$it.find('.like-icon').removeClass('liked');
}
// 点赞数目
$it.find('.like .num').text(it.praise_num);
// 评论数目
$it.find('.comment em').text(it.comment_num);
}
}
}
}
(function() {
'use strict';
var idArr = [];
$msgs.children('.msg-content').each(function() {
var id = $(this).data('id');
if (id) {
idArr.push(id);
}
});
getDynamicByIds(idArr.join(',')).then(renderData);
}());
... ...
/**
* 逛编辑页、列表页
* @author: xuqi<qi.xu@yoho.cn>
* @date: 2015/12/15
*/
require('./msg');
require('./img-blink');
require('./right-side');
// page cache下更新点赞状态、点赞数、评论数、阅读数
require('./list-dynamic');
... ...
var $ = require('yoho-jquery'),
lazyLoad = require('yoho-jquery-lazyload');
var prising;
require('yoho-jquery-dotdotdot');
// 资讯文字截取和lazyload
function dotLazy() {
// 文字截取
$('.msg-title, .msg-content .content').dotdotdot({
wrap: 'letter'
});
// Lazyload
lazyLoad($('#msg-list img.lazy'));
}
// 资讯点赞
$('.guang-page').on('click', '.like-icon', function() {
var $this = $(this),
msgId = $this.closest('.msg-content').data('id'),
url;
// 同一资讯多次点击归一处理
if (prising === msgId) {
return;
}
prising = msgId;
$this.toggleClass('liked');
// 点赞或取消点赞
if ($this.hasClass('liked')) {
url = '/guang/info/praise';
} else {
url = '/guang/info/cancelPraise';
}
$.ajax({
type: 'GET',
url: url,
data: {
id: msgId,
time: new Date().getTime()
}
}).then(function(data) {
if (data.code === 200) {
if (data.data * 1 === 0) {
$this.next('b').addClass('num-0').children('.num').html('0'); // 隐藏数字显示
} else {
$this.next('b').removeClass('num-0').children('.num').html(data.data);
}
}
prising = false;
});
}).on('mouseenter mouseleave', '.like-icon', function() {
$(this).closest('.like').toggleClass('hover');
});
dotLazy();
exports.dotLazy = dotLazy;
... ...
/**
* 右侧栏文字截取js
*/
var $ = require('yoho-jquery'),
lazyLoad = require('yoho-jquery-lazyload');
require('yoho-jquery-dotdotdot');
$('.ex-reco-context').dotdotdot({
wrap: 'letter'
});
lazyLoad($('.ads img.lazy'));
... ...
@use postcss-crip;
@use postcss-short;
.pager {
fz: 12px;
a {
h: 24px;
p: 0 9px;
lh: 24px;
d: inline-block;
ta: center;
mr: 8px;
c: #222;
&.cur {
c: #fff #222;
}
&:first-child .iconfont {
right: auto;
left: -5px;
}
}
.iconfont {
position: relative;
vertical-align: middle;
bottom: 1px;
right: -5px;
font-size: 14px;
}
}
\ No newline at end of file
... ...
.path-nav {
font-size: 12px;
padding: 15px 0;
height: 18px;
line-height: 18px;
/*border-bottom: 1px solid #eaeceb;*/
/*margin-bottom: 15px;*/
color: #666;
a {
color: #666;
}
.iconfont {
font-size: 12px;
}
.last {
font-weight: bold;
}
}
\ No newline at end of file
... ...
.guang-detail-page {
width: 1150px;
margin: 0 auto 95px;
b {
font-weight: bold;
}
i {
font-style: italic;
}
.block {
margin: 15px 0;
}
.excellent-recommendation-title {
margin-top: 4px;
}
.block-header {
position: relative;
border-bottom: 1px solid #c1c1c1;
font-size: 18px;
height: 38px;
line-height: 38px;
text-align: center;
margin-bottom: 24px;
color: #333;
.more-reco {
position: absolute;
right: 0;
color: #000;
font-size: 14px;
text-decoration: none;
}
}
/*830+22:兼容IE8不认识:nth-child导致brand换行的问题*/
.related-brand .brands {
width:852px;
}
.related-reco .recos {
width: 850px;
}
.detail-title {
font-size: 28px;
line-height: 64px;
border-bottom: 1px dotted #c1c1c1;
word-wrap:break-word;
}
.article-author {
float: left;
line-height: 64px;
.author-avatar {
clear: both;
width: 38px;
height: 64px;
img {
width: 38px;
height: 38px;
border-radius: 50%;
vertical-align: middle;
}
}
}
.author-info {
float: left;
margin-left: 10px;
font-size: 14px;
max-width: 447px;
.author-name {
display: block;
height: 64px;
line-height: 64px;
cursor: pointer;
color: #000;
&:hover {
color: #cc3300;
}
}
.author-introduce {
color: #999;
}
}
.article-status {
float: right;
height: 64px;
line-height: 64px;
color: #999;
font-size: 13px;
.article-click {
margin: 0 25px;
}
.article-comment {
color: #cc3300;
cursor: pointer;
}
}
.article-main {
img {
display: block;
max-width: 100%;
margin:0 auto;
}
.article-text {
margin: 2px 0 20px;
line-height: 28px;
font-size: 14px;
}
.article-small-pic {
text-align: center;
font-size: 0;
img {
display: inline-block;
max-width: 412px;
&:first-child {
margin: 0 6px 0 0;
}
}
}
.block:first-child {
margin-top: 10px;
}
}
/*user handle*/
.user-handle {
margin: 30px 0 0 0;
text-align: center;
ul {
display: inline-block;
li {
float: left;
margin: 0 15px;
cursor: pointer;
a {
position: relative;
display: block;
padding: 0 10px;
height: 36px;
line-height: 36px;
color: #535353;
font-size: 0;
background: #efefef;
text-align: left;
i, span{
display: inline-block;
font-style: normal;
font-size: 14px;
}
i {
margin: 0 5px 0 0;
font-size: 18px;
opacity: 0.5;
}
.cancel-collect {
display: none;
}
}
}
.like-status.liked i,
.like-status.hover i{
opacity: 1;
}
.like-statis.hover .like-num {
color: #000;
}
.sort-collect a {
i {
width: 21px;
}
}
.sort-collect.collected a {
i {
opacity: 1;
}
span {
display: none;
}
.cancel-collect {
display: inline;
}
}
.sort-collect.hover i {
opacity: 1;
}
.sort-collect.hover span {
color: #000;
}
}
}
.article-bottom-info {
margin: 44px 0 0 0;
padding: 0 0 10px;
border-bottom: 1px dotted #c1c1c1;
}
.article-tag {
float: left;
width: 588px;
.tag-icon {
float: left;
margin: 0 12px 0 0;
font-size: 20px;
font-style: normal;
}
ul {
float: left;
max-width: 555px;
li {
float: left;
margin: 0 10px 10px 0;
a {
display: block;
padding: 0 15px;
height: 20px;
line-height: 20px;
font-size: 12px;
color: #fff;
font-weight: bold;
background: #c1c1c1;
}
&:hover a {
background:#333;
}
}
li:first-child {
margin-left: 0;
}
}
}
.article-share {
float: right;
.title {
font-size: 12px;
}
}
.detail-related-posts {
margin: 14px 0 0 0;
li {
float: left;
width: 264px;
margin-left: 19px;
a {
display: block;
}
.bg-img {
display: block;
width: 100%;
height: 173px;
line-height: 173px;
text-align: center;
font-size: 0;
img {
max-width: 100%;
max-height: 100%;
vertical-align: middle;
}
}
.post-title {
margin: 8px 0 0 0;
h2 {
line-height: 16px;
font-size: 14px;
color: #000;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.post-title:hover h2 {
color: #cc3300 !important;
}
}
li:first-child {
margin-left: 0;
}
}
.comment-area {
margin: 58px 0 0 0;
.comment-publish {
height: 48px;
}
}
.comment-textarea {
textarea {
display: block;
width: 812px;
height: 86px;
padding: 12px 12px;
resize: none;
outline: none;
font-size: 14px;
line-height: 18px;
color: #535353;
font-family: "arial","helvetica","微软雅黑";
border: 1px solid #e7e7e7;
}
}
.word-count-tip {
display: inline-block;
height: 48px;
line-height: 48px;
font-size: 12px;
color: #c8c8c8;
.exceed-count {
color: #f00;
}
}
.publish-btn {
margin: 10px 0 0 0;
float: right;
width: 90px;
height: 33px;
line-height: 33px;
text-align: center;
color: #fff;
font-size: 14px;
background: #cb3a3e;
cursor: pointer;
&:hover {
background: #c03234;
}
&.disable {
background-color: #e79c9e;
}
}
.comments-wrap {
h4 {
position: relative;
line-height: 32px;
border-bottom: 1px solid #e7e7e7;
.comment-num {
margin-right: 5px;
color: #c11e00;
}
i {
position: absolute;
width: 13px;
height: 7px;
left: 30px;
bottom: -7px;
background: resolve('guang/comment-icon.png') no-repeat;
}
}
.comment-pager {
float: right;
margin: 20px 0;
}
}
.comments-empty {
display: none;
color: #ccc;
margin: 20px 0;
font-size: 12px;
line-height: 12px;
text-align: center;
}
.commnets-resultwrapper {
display: none;
}
.comments-list{
li{
margin: 14px 0 0;
padding: 0 0 15px;
border-bottom: 1px dotted #e7e7e7;
.avatar{
float: left;
width: 40px;
height: 40px;
overflow: hidden;
img{
display: block;
width: 100%;
height: 100%;
border-radius: 50%;
}
}
.comment-info{
float: left;
width: 774px;
margin: 0 0 0 16px;
.comment-user-name{
color: #c11e00;
font-size: 15px;
line-height: 15px;
}
.comment-content{
margin-top: 10px;
line-height: 16px;
font-size: 12px;
word-wrap:break-word;
}
.comment-time{
margin: 10px 0 0 0;
color: #c8c8c8;
font-size: 12px;
line-height: 12px;
clear: both;
}
}
}
}
.brand {
margin-right: 22px;
margin-bottom: 20px;
float: left;
.thumb {
display: table-cell;
border: 1px solid #f5f5f5;
height: 120px;
width: 120px;
box-sizing: border-box;
text-align: center;
vertical-align: middle;
img {
display: block;
max-width: 120px;
max-height: 120px;
margin: 0 auto;
}
}
.brand-name {
width: 120px;
font-size: 13px;
line-height: 20px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
text-align: center;
color: #333;
}
}
$commodityWidth: 192px;
.tag-container,
.few-tag {
display: none;
}
.good-info {
width: $commodityWidth;
margin-right: 20px;
margin-bottom: 12px;
.good-detail-img {
height: auto;
.good-thumb,
img.lazy {
height: 257px;
}
}
.good-detail-text > a {
margin-top: 0;
line-height: 36px;
}
.good-detail-text > .price {
margin-top: 0;
}
.good-detail-text .brand{
margin-right:0;
margin-bottom:0;
}
}
}
... ...
.guang-index-page {
.msg-nav {
border-bottom: 1px solid #000;
margin-top: 24px;
height: 30px;
li {
float: left;
height: 30px;
line-height: 30px;
text-align: center;
font-size: 18px;
padding: 0 28px;
a {
display: block;
height: 100%;
width: 100%;
color: #333;
}
&.actived {
background-color: #111;
a {
color: #fff;
}
}
}
}
.msg-pager {
float: right;
margin: 20px 0;
}
}
\ No newline at end of file
... ...