detail-product-api.js 8.78 KB
/**
 * Created by TaoHuang on 2016/6/14.
 */

'use strict';

const config = global.yoho.config;
const redis = global.yoho.redis;
const cache = global.yoho.cache;
const logger = global.yoho.logger;
const helpers = global.yoho.helpers;
const _ = require('lodash');
const $ = require('cheerio');

const SearchServiceModel = require('./search-api');
const GuangServiceModel = require('../../guang/models/guang-service');
const productProcess = require('../../../utils/product-process');
const uuid = require('uuid');

const specialDescCache = {};

function _cacheGet(key) {
    return cache.get(key).then((data) => {
        if (data) {
            return JSON.parse(data);
        }

        return Promise.reject();
    });
}

const ONE_HOUR = 60 * 60; // 一小时
const ONE_DAY = ONE_HOUR * 24; // 一天
const HALF_MONTH = ONE_DAY * 15; // 半个月

function _cacheSave(key, value, ttl) {
    return cache.set(key, value, ttl)
        .catch(err => logger.error(`save cache data fail:${err.toString()}`));
}

function _cached(fn, ctx, ttl = HALF_MONTH) {
    const pre = 'recommend-cache:' + (fn.name || 'random:' + uuid.v4()) + ':';

    return function() {
        const args = Array.prototype.slice.call(arguments);
        const key = pre + JSON.stringify(args || '[]');

        if (!_.get(this.ctx.req.app.locals.pc, 'ci.tdk', false)) {
            return Promise.resolve();
        }

        return _cacheGet(key).catch(() => {
            return fn.apply(ctx, args).then(result => {
                _cacheSave(key, result, ttl);
                return result;
            });
        });
    };
}


module.exports = class extends global.yoho.BaseModel {
    constructor(ctx) {
        super(ctx);

        this.searchApi = new SearchServiceModel(ctx);
        this.guangService = new GuangServiceModel(ctx);

        this.getNewProduct = _cached(this._getNewProduct, this);
        this.getGuangArticles = _cached(this._getGuangArticles, this);
        this.getRecommendHotKeywords = _cached(this._getRecommendHotKeywords, this);
        this.getRecommendKeywords = _cached(this._getRecommendKeywords, this);
        this.getShopRecommendAsync = _cached(this._getShopRecommendAsync, this, ONE_DAY);
    }

    /**
     * 商品的 banner
     */
    getProductBannerAsync(pid) {
        return this.get({
            data: {
                method: 'web.productBanner.data',
                product_id: pid
            }, param: config.apiCache

        });
    }

    /**
     * 商品尺寸
     */
    sizeInfoAsync(skn) {
        return this.get({
            data: {
                method: 'h5.product.intro',
                productskn: skn
            }, param: config.apiCache
        });
    }

    /**
     * 特殊商品退换货
     */
    isSupportReturnedSale(skn) {
        return this.get({
            data: {
                method: 'web.product.refundExchange',
                product_skn: skn
            }, param: config.apiCache
        });
    }

    isSupportService(skn) {
        return this.get({
            data: {
                method: 'app.product.supportService',
                product_skn: skn
            }, param: config.apiCache
        });
    }

    /**
     * 商品舒适度
     */
    getProductComfortAsync(pid) {
        return this.get({
            data: {
                method: 'web.productComfort.data',
                product_id: pid
            }, param: config.apiCache
        });
    }

    /**
     * 模特试穿
     */
    getProductModelTryAsync(skn) {
        return this.get({
            data: {
                method: 'web.productModelTry.data',
                product_skn: skn
            }, param: config.apiCache
        });
    }

    /**
     * 获得产品信息
     */
    getProductAsync(id, uid, isStudents, vipLevel) {

        let data = {
            method: 'app.product.data'
        };

        if (id.skn) {
            data.product_skn = id.skn;
        }

        if (id.pid) {
            data.product_id = id.pid;
        }

        if (uid) {
            data.uid = uid;
        }

        if (isStudents) {
            data.is_student = isStudents;
        }

        if (vipLevel) {
            data.current_vip_level = vipLevel;
        }

        return this.get({ data, param: config.apiCache });
    }

    /**
     * 促销信息
     */
    getPromotionAsync(skn) {
        let data = {
            method: 'app.product.promotion',
            product_skn: skn
        };

        return this.get({ data, param: config.apiCache });
    }

    /**
     * 限购商品
     */
    getLimitedProductStatusAsync(code, uid, skn) {
        let data = {
            method: 'app.limitProduct.productStatus',
            limitProductCode: code
        };

        if (uid) {
            data.uid = uid;
        }

        if (skn) {
            data.product_skn = skn;
        }

        return this.get({ data, param: config.apiCache });
    }

    /**
     * 店铺推荐
     */
    _getShopRecommendAsync(skn) {
        return this.get({
            data: {
                method: 'web.product.shopRecommend',
                product_skn: skn,
                page: 1,
                limit: 20
            }
        });
    }

    /**
     * 套餐和量贩
     */
    getBundleAsync(skn) {
        return this.get({
            data: {
                method: 'app.query.bundleSkn',
                product_skn: skn
            }
        });
    }

    /**
     * 找相似
     */
    getLikeAsync(skn, limit) {
        return this.get({
            data: {
                method: 'web.search.findLike',
                limit: limit || 10,
                product_skn: skn
            }, param: {
                cache: 86400
            }
        });
    }

    /**
     * 特别说明
     */
    getSpecialDesc(skn) {
        let now = new Date().getTime();

        if (specialDescCache.time && now - specialDescCache.time < ONE_HOUR * 1000) {
            return Promise.resolve(specialDescCache.value);
        }

        return this.get({
            data: {
                method: 'app.product.intro',
                product_skn: skn,
                app_version: '5.6.0'
            },
            param: {cache: true}
        }).then(result => {
            result = _.isString(result) ? result : '';
            result = $.load(result);

            result = result('.price-description > .price-desc-detail');

            specialDescCache.time = now;
            specialDescCache.value = result.html() || '';

            return specialDescCache.value;
        });
    }

    // 根据mid_sort从redis获取分类下的hot关键词
    _getRecommendHotKeywords(midSort, skn) { // eslint-disable-line
        return redis.all([['get', `global:yoho:seo:hot:keywords:${midSort}:page`]]).then(res => {
            return redis.all([
                ['get', `global:yoho:seo:hot:keywords:${midSort}:page:${ _.random(1, res[0]) || 1}`]
            ]);
        }).then(res => {
            return this._getKeywordsInfo(JSON.parse(res[0] || '[]'));
        });
    }

    // 根据small_sort从redis获取分类下的关键词
    _getRecommendKeywords(smallSort, skn) { // eslint-disable-line
        return redis.all([['get', `global:yoho:seo:keywords:sortId:${smallSort}:page`]]).then(res => {
            return redis.all([
                ['get', `global:yoho:seo:keywords:sortId:${smallSort}:page:${ _.random(1, res[0]) || 1}`]
            ]);
        }).then(res => {
            return this._getKeywordsInfo(JSON.parse(res[0] || '[]'));
        });
    }

    // 返回6条推荐关键词页面
    _getKeywordsInfo(keywords) {
        let res = [];

        _.forEach(_.slice(_.shuffle(keywords), 0, 18), val => {
            res.push({
                url: helpers.urlFormat(`/${val.is_hot ? 'hot' : 'chanpin'}/${val.id}.html`),
                keyword: val.keyword
            });
        });
        return res;
    }

    _getNewProduct(sort) { // eslint-disable-line
        return this.searchApi.getProductList({
            limit: 10,
            order: 's_t_desc',
            page: _.random(1, 6000)
        }).then(result => {
            if (result.code === 200) {
                return productProcess.processProductList(result.data.product_list);
            }

            return [];
        }).then(productList => {
            return productList.map((it) => ({
                url: it.url,
                name: it.product_name
            }));
        });
    }

    _getGuangArticles(skn) {  //eslint-disable-line
        return this.guangService.getArticleList(
            3, null, null, null, _.random(1, 700), null, null, 4, null, null
        ).then(result => {
            return _.get(result, 'msgs', []).map((article) => ({
                url: article.url,
                name: article.title,
                img: article.img.replace(/\?.*$/g, '?imageView2/1/w/{width}/h/{height}/q/90')
            }));
        });
    }
};