header.js 7.85 KB
/**
 * header model
 * @author: 赵彪<bill.zhao@yoho.cn>
 * @date: 2016/05/03
 */

'use strict';

const _ = require('lodash');

const serviceApi = global.yoho.ServiceAPI;
const helpers = global.yoho.helpers;
const Handlebars = require('handlebars');
const path = require('path');
const headerHtml = require('fs').readFileSync(path.resolve(__dirname, '../views/partial/headerNew.hbs')).toString();
const template = Handlebars.compile(headerHtml);
const logger = global.yoho.logger;

/**
 * 获取菜单
 * @param undefined
 * @return {array} 菜单数组
 */
const getMenuData = () => (
    [{
        link: 'http://www.yoho.cn',
        cn: '集团官网',
        en: 'YOHO!'
    }, {
        link: 'http://www.yohoboys.com',
        cn: '男生潮流',
        en: 'YOHO!BOYS'
    }, {
        link: 'http://www.yohogirls.com',
        cn: '女生潮流',
        en: 'YOHO!GIRLS'
    }, {
        link: 'http://www.yohomars.com',
        cn: '新鲜好去处',
        en: 'Mars'
    }, {
        link: 'http://www.yohood.cn',
        cn: '潮流嘉年华',
        en: 'YO\'HOOD'
    }]
);

/**
 * 获取导航
 * @param {Object} data 要处理的数据
 * @param {String} type 频道类型
 * @return {array} 导航数组
 */
const getNavBar = (data, type) => {
    let navBars = [];

    _.forEach(data, item => {
        let obj = {};
        let lowEn = _.camelCase(item.sort_name_en).toLowerCase();

        Object.assign(obj, {
            type: lowEn,
            link: item.sort_url,
            cn: item.sort_name,
            en: item.sort_name_en,
            isNewPage: item.is_new_page === 'Y'
        });

        if (type === lowEn) {
            obj.active = true;
        }

        // 奥莱频道显示图片,特殊处理
        if (lowEn === 'outlets') {
            obj.ico = item.sort_ico;
        }

        navBars.push(obj);
    });

    return navBars;
};


/**
 * 获取品牌名字
 * @param {Object} data 要处理数据
 * @return {array} 品牌数组
 */
const getBrandItems = (data) => {
    let brandItems = [];

    _.forEach(data, item => {
        let obj = {
            link: '',
            hot: false,
            brandName: ''
        };

        obj.link = item.sort_url;
        obj.hot = item.is_hot === 'Y' ? true : false;
        obj.brandName = item.sort_name;

        brandItems.push(obj);
    });


    return brandItems;
};

/**
 * 获取三级菜单
 * @param {Object} data 要处理数据
 * @return {array} 三级菜单数组
 */
const getThirdNav = (data) => {
    let thirdNav = [];

    _.forEach(data, item => {
        let obj = {
            link: '',
            title: '',
            brandItems: false
        };

        obj.link = item.sort_url;
        obj.title = item.sort_name;


        if (item.sub) {
            obj.brandItems = getBrandItems(item.sub);
        }

        thirdNav.push(obj);
    });


    return thirdNav;
};

/**
 * 获取子菜单
 * @param {Object} data 要处理数据
 * @param {String} type 频道类型
 * @return {array} 子菜单数组
 */
const getSubNavGroup = (data, type) => {
    let subNavGroup = [];

    _.forEach(data, it => {
        let subNav = [];

        _.forEach(it.sub, item => {
            let obj = {};

            obj.link = item.sort_url;
            obj.name = item.sort_name;
            obj.isHot = item.is_hot === 'Y' ? true : false;
            obj.isNew = item.is_new === 'Y' ? true : false;

            if (item.sub) {
                obj.thirdNav = getThirdNav(item.sub);
                obj.imgCode = item.content_code;
            }

            subNav.push(obj);
        });

        let lowEn = _.camelCase(it.sort_name_en).toLowerCase();

        subNavGroup.push({
            subType: lowEn,
            subNav: subNav,
            active: lowEn === type
        });
    });

    return subNavGroup;
};


/**
 * 处理接口返回的数据
 * @param {object} 接口返回的对象
 * @param {String} 指定页面类型为boys,girls,kids,lifestyle
 * @return {object} 头部数据
 */
const setHeaderData = (resData, type) => (
    {
        header: true,
        headType: type,
        yohoGroup: getMenuData(),
        navbars: resData ? getNavBar(resData, type) : [],
        subNavGroup: resData ? getSubNavGroup(resData, type) : []
    }
);

/**
 * 请求头部数据
 * @param {String} 频道类型
 * @return {promise}
 */
const cacheHeaderHtml = {};
const THIRTY_MINUTES = 1000 * 60 * 10;


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

    getHotSearchAsync(channel) {
        return this.get({
            data: {
                method: 'app.search.getTerms',
                yh_channel: channel
            },
            param: {
                cache: 600,
                code: 200
            }
        });
    }

    getHeaderNavAsync() {
        return this.get({
            url: 'operations/api/v6/category/getCategory',
            data: {},
            param: {
                cache: true,
                code: 200
            },
            api: serviceApi
        });
    }
    async requestHeaderData(type, noH1) {
        const usableType = ['boys', 'girls', 'kids', 'lifestyle'];
        let resData = {disHeaderH1: noH1};
        let _html;

        if (usableType.indexOf(type) < 0) {
            type = usableType[0];
        }

        let cacheKey = noH1 ? `${type}_noh1` : type;

        let cacheData = cacheHeaderHtml[cacheKey];

        if (!cacheData) {
            cacheHeaderHtml[cacheKey] = [];
            cacheData = [];
        }

        if (_.isEmpty(cacheData[0]) || ((new Date() - cacheData[1]) > THIRTY_MINUTES)) {
            let channelNum = (function() {
                switch (type) {
                    case 'boys':
                        return 1;
                    case 'girls':
                        return 2;
                    case 'kids':
                        return 3;
                    case 'lifestyle':
                        return 4;
                    default:
                        return 1;
                }
            }());

            let res = await Promise.all([
                this.getHeaderNavAsync(),
                this.getHotSearchAsync(channelNum)
            ]);

            resData.headerData = {};

            if (res[0] && res[0].data) {
                Object.assign(resData.headerData, setHeaderData(res[0].data, type));
            } else {
                logger.error('header api data empty');
            }

            if (res[1] && res[1].data) {
                resData.headerData.defaultSearch = _.get(res[1], 'data.defaultTerms[0].content', '');
                if (channelNum === 4) {
                    resData.headerData.defaultSearch = '';
                }
                resData.headerData.hotTerms = _.map(_.get(res[1], 'data.hotTerms', []), (value) => {
                    return {
                        href: helpers.urlFormat('', {query: value.content}, 'search'),
                        content: value.content,
                        sort: value.sort,
                        status: value.status,
                        type: value.type
                    };
                });
            } else {
                logger.error('search terms api data empty');
            }

            if (_.isEmpty(_.get(resData, 'headerData.navbars')) && cacheData[0]) {
                _html = cacheData[0];
            } else {
                _html = template(resData);
                cacheHeaderHtml[cacheKey] = [_html, new Date()];
            }
        } else {
            _html = cacheData[0];
        }

        return Promise.resolve({headerData: _html});
    }

    getSubNavGroupData(type) {
        const usableType = ['boys', 'girls', 'kids', 'lifestyle'];

        if (usableType.indexOf(type) < 0) {
            type = usableType[0];
        }

        return this.getHeaderNavAsync().then(result => {
            return getSubNavGroup(result.data, type) || [];
        });
    }
};