/** * 逛 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 urlHelper = require('./url-helper'); const videoPlayerTpl = require('../helpers/video-player-tpl'); const helpers = global.yoho.helpers; const redis = global.yoho.redis; 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' }; module.exports = class extends global.yoho.BaseModel { constructor(ctx) { super(ctx); } /** * 获取首页频道nav */ 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!有货' }; } getPathNav(channelType, query) { let path = _.concat( this.getHomeChannelNav(channelType), [{ name: '逛', pathTitle: '逛', href: helpers.urlFormat('/guang/', null) }] ); return query ? _.concat(path, [{ name: query, pathTitle: query}]) : path; } _formatTag(tagData) { let name = tagData.name; return { tag: name, name: name, url: encodeURI(helpers.urlFormat(`/guang/tags/${name}/`, null)) }; } /** * 格式化资讯文章 * * @param array $articleData 需要格式化的资讯数据 * @param bool $showTag 是否显示左上角标签 * @param bool $showAuthor 控制是否显示作者信息 * @return array | false */ _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: _.get(articleData, 'min_category_name') || _.get(articleData, 'category_name'), // isReco: articleData.is_recommended && Number(articleData.is_recommended) === 1 ? true : false, url: +articleData.category_id === 9999 ? helpers.getUrlBySkc(_.get(articleData, 'product_list[0].product_skn', 0)) : ghelper.getArticleUrl(articleData.url, articleData.id), 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, isVideo: articleData.category_name === '视频' ? true : false }; if (showTag && articleData.category_id) { switch (String(articleData.category_id)) { 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 '19': // 专题 result.isSpecialTopic = true; break; default: break; } } if (!articleData.author) { articleData.author = { name: '', avatar: '' }; } result.author = articleData.author.name; let authorId = articleData.author.author_id; if (authorId) { result.editorUrl = urlHelper.editorUrl(channel, authorId); } let tags = []; if (articleData.tags) { let aTags = articleData.tags; for (let i = 0; i < aTags.length; i++) { tags.push(this._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; } _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('/guang/info/index', param), title: adData.title, bgColor: adData.bgColor }; } /** * 获取页文章数据 * @param {String} channelType 传入频道页类型,值可以是: boys, girls, kids, lifestyle * @return {Object} */ 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 this.get({ url: 'guang/api/v2/article/getList', data: param, param: { cache: useCache ? 300 : false }, api: global.yoho.ServiceAPI }).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 => this._formatArticle(it, true, false, channel)); } if (list.adlist) { adsList = _.map(list.artList, it => this._formatAd(it, channel)); } } return { msgs: artList, ads: adsList, total: total }; } return null; }); } getFirstArticleList(...params) { let id = params.pop(); return this.getArticleList(...params).then(rdata => { return _.compact(_.map(_.get(rdata, 'msgs', []), msgs => { if (msgs.id === id) { return null; } return { url: msgs.url, img: msgs.img, thumb: msgs.img, title: msgs.title, }; })); }); } /** * 获取最新置顶文章 */ getTopList(gender, uid, udid, page, useCache) { uid = uid || 0; udid = udid || ''; page = page || 1; useCache = useCache || false; let param = { gender: gender, uid: uid, udid: udid, page: page, client_type: 'web' }; return this.get({ url: 'guang/api/v2/article/getTopList', data: param, param: { cache: useCache ? 300 : false }, api: global.yoho.ServiceAPI }).then(res => { if (res && res.data) { let artList, 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 => this._formatArticle(it, true, false, '')); } } return { msgs: artList, total: total }; } return null; }); } /** * 获取热门标签数据 * @param {String} type 传入频道页类型,值可以是: boys, girls, kids, lifestyle * @return {Object} */ getHotTags(page, limit, channel, isDegrade) { let data = { client_type: 'web', page: page || 1, limit: limit || 10 }; if (isDegrade) { return null; } return this.get({ url: 'guang/api/v2/article/getTagTop', data: data, param: { cache: true }, api: global.yoho.ServiceAPI }).then(res => { return _.map((res && res.data) || [], it => { let name = it.tag_name; return { tagName: it.tag_name, url: encodeURI(helpers.urlFormat(`/guang/tags/${name}/`, null)) }; }); }); } /** * 获取广告数据 * @param {String} channelType 传入频道页类型,值可以是: boys, girls, kids, lifestyle * @return {Object} */ getAds(channelType, isDegrade) { let contentCode = ADS_CODE[channelType] || ADS_CODE.boys; if (isDegrade) { return null; } let data = { content_code: contentCode }; return this.get({ url: URL_OPERATIONS_RESOURCE_GET, data: data, param: { cache: true }, api: global.yoho.ServiceAPI }).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} */ getBanner(channelType) { let contentCode = BANNER_CODE[channelType] || BANNER_CODE.boys; let data = { content_code: contentCode }; return this.get({ url: URL_OPERATIONS_RESOURCE_GET, data: data, param: { cache: true }, api: global.yoho.ServiceAPI }).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; }); } getCategory(currentSortId, channel) { currentSortId = currentSortId || 0; return this.get({ url: 'guang/api/v1/category/get', param: { cache: true }, api: global.yoho.ServiceAPI }).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: urlHelper.listUrl(channel, cat.id) }); } list.push({ typeId: 0, type: '资讯', isActive: false, navUrl: helpers.urlFormat('/guang/news') }); } return list; }); } /** * 推荐文章 */ getRecoArticles(gender, page, limit) { let data = { gender: gender, page: page, limit: limit }; return this.get({ url: 'guang/api/v2/article/getArticleByViewsNum', data: data, param: { cache: true }, api: global.yoho.ServiceAPI }).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), title: it.title }; if (it.src) { reco.img = helpers.image(it.src, 90, 60, 1); } list.push(reco); } } return list; }); } /** * 获取作者信息 */ getAuthor(channel, authorId) { let data = { author_id: authorId }; return this.get({ url: 'guang/service/v1/author/getAuthor', data: data, param: { cache: 3600 }, api: global.yoho.ServiceAPI }).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 ? urlHelper.editorUrl(channel, authorId) : '' }; } }); } /** * 获取文章基本信息,文章标题(不含内容) */ getArticleInfo(aid, channel) { let data = { article_id: aid }; return this.get({ url: 'guang/service/v2/article/getArticle', data: data, param: { cache: true }, api: global.yoho.ServiceAPI }).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(this._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 }; } }); } _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: (val.is_global !== 'Y') ? helpers.getUrlBySkc(val.product_skn) : helpers.urlFormat(`/product/global/${val.product_skn}.html`, null) }; 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 */ getProductList(params, arr) { let data = { method: 'app.search.recomandLi', order: 's_n_desc', client_type: 'web', limit: 60 }; Object.assign(data, params); return this.get({ data: data, param: { cache: true } }).then(ret => { if (ret && ret.code === 200 && ret.data && ret.data.product_list) { return this._formatProduct(ret.data.product_list, arr); } }); } _articleContentFormat() { return { goods: goods=> { let productSkn = [], arr = {}; _.forEach(goods, val => { productSkn.push(val.id); arr[val.id] = val.src; }); if (productSkn.length > 0) { return this.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) { if (it) { productSkn.push(it.id); arr[it.id] = it.src; } } if (productSkn.length) { // 包含多个对象,每对象里list都取数据,最终每个list只取前4个 result.push(this.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; }, video: data => { let result = { video: [] }; result.video.push(videoPlayerTpl((data.src).replace(/http:/g, ''), 640, 350)); return result; }, 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: () => ({}) }; } /** * 获取文章内容详情 */ getArticleContent(aid, title) { let that = this; let content = [], index = 0; let data = { article_id: aid }; return redis.all([ ['get', `global:yoho:guang:detail:${aid}`] ]).then(redisData => { redisData = JSON.parse(redisData[0] || '{}'); if (!redisData.data) { return this.get({ url: 'guang/service/v2/article/getArticleContent', data: data, param: { cache: true }, api: global.yoho.ServiceAPI }); } return redisData; }).then(res => { // 内容内推荐的商品 let gpromises = [], ggpromises = []; if (res && res.code === 200 && res.data) { let altNum = 0; _.forEach(res.data, (it) => { _.forEach(it, (val, key) => { if (key === 'goods') { gpromises.push( that._articleContentFormat().goods(_.union(val.data, val.dataGlobal, val.dataLimit))); return; } else if (key === 'goodsGroup') { // 可能包含多个list,则有多个promise ggpromises = ggpromises.concat(that._articleContentFormat().goodsGroup(val.data)); } else { let other = _.isFunction(that._articleContentFormat()[key]) ? that._articleContentFormat()[key](val.data) : ''; if (other) { // 前五张图片添加alt if (altNum < 6 && (other.pic || other.smallPic)) { other.alt = title; altNum += other.pic ? 1 : other.smallPic.length; } 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 */ getArticleBaseInfo(aid, uid, udid) { let data = { id: aid, uid: uid, udid: udid }; return this.get({ url: 'guang/api/v1/article/getArticleBaseInfo', data: data, api: global.yoho.ServiceAPI }).then(res => ({ isLike: res && res.isPraise === 'Y', likeNum: res.praise_num || 0, isCollected: res && res.isFavor === 'Y' })); } /** * 文章相关品牌 * @param $articleId * @param bool $onlyUrl * @return mixed */ getArticleRelateBrand(aid) { let data = { article_id: aid }; return this.get({ url: 'guang/service/v2/article/getBrand', data: data, param: { cache: true }, api: global.yoho.ServiceAPI }).then(res => { if (res && res.code === 200 && res.data) { return _.map(res.data, it => { it.thumb = it.thumb; it.url = (it.isGlobal !== 'Y') ? it.url : helpers.urlFormat('/product/global/list', {brand: it.tbl_id}); return it; }); } }); } /** * 相关文章列表 * @param $articleId * @param $tag * @param int $limit * @param bool $onlyUrl * @return mixed */ getRelateArticleList(aid, tag, size) { size = size || 3; let data = { article_id: aid, tags: tag, limit: size }; return this.get({ url: 'guang/service/v2/article/getOtherArticle', data: data, param: { cache: true }, api: global.yoho.ServiceAPI }).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); return it; }); } }); } /** * 获取文章评论数据 */ getArticleComments(udid, uid, aid, page, pageSize) { udid = udid || 0; uid = uid || 0; page = page || 1; pageSize = pageSize || 20; let data = { udid: udid, uid: uid, article_id: aid, page: page, limit: pageSize }; return this.get({ url: 'guang/api/v1/comments/getList', data: data, api: global.yoho.ServiceAPI }).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('/guang/info/index', { id: aid, pageSize: pageSize }) }; }); } /** * 文章评论提交 * @param $id * @param $uid * @return mixed */ addComment(aid, uid, content) { let data = { article_id: aid, uid: uid, content: content }; return this.get({ url: 'guang/api/v1/comments/add', data: data, api: global.yoho.ServiceAPI }).then(res => { if (res && res.code === 200) { return res.data; } else { return Promise.reject('评论失败'); } }); } /** * 文章点赞 * @param $id * @param $uid * @return mixed */ praise(aid, udid) { let data = { article_id: aid, udid: udid }; return this.get({ url: 'guang/api/v2/praise/setPraise', data: data, api: global.yoho.ServiceAPI }); } /** * 文章点赞 * @param $id * @param $uid * @return mixed */ cancelPraise(aid, udid) { let data = { article_id: aid, udid: udid }; return this.get({ url: 'guang/api/v2/praise/cancel', data: data, api: global.yoho.ServiceAPI }); } /** * 收藏文章 * @param $id * @param $uid * @return mixed */ collect(aid, uid) { let data = { article_id: aid, uid: uid }; return this.get({ url: 'guang/api/v1/favorite/setFavorite', data: data, api: global.yoho.ServiceAPI }); } /** * 取消收藏文章 * @param $id * @param $uid * @return mixed */ cancelCollect(aid, uid) { let data = { article_id: aid, uid: uid }; return this.get({ url: 'guang/api/v1/favorite/cancelFavorite', data: data, api: global.yoho.ServiceAPI }); } /** * 获取制指定文章的动态信息 * @param ids * @returns {Promise.<T>|*} */ getDynamicDataById(id, uid, udid) { let data = { id: id, uid: uid, udid: udid }; return this.get({ url: 'guang/api/*/article/getArticlePraiseAndFavor', data: data, api: global.yoho.ServiceAPI }); } /** * 获取制指定文章的动态信息 * @param ids * @param udid * @param other [Obejct] 包含uid,query,type等非必传参数 * @returns {Promise.<T>|*} */ 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 this.get({ url: 'guang/api/*/article/getSimpleArticleList', data: params, api: global.yoho.ServiceAPI }); } };