price-day-task.js 4.03 KB
const {ProductRelationModel} = require('../../models');
const _ = require('lodash');
const dayjs = require('dayjs');
const sizeRelation = require('../../data/size.json');
const lockup = require('node-lockup');
const {mysqlPool} = require('../../libs/mysql');
const {logger} = require('../../libs/logger');
const spiderSj = require('./spider/shenjian');
const spiderDu = require('./spider/du');
const spiderUfo = require('./spider/ufo');

const mergePrice = (prices, scales) => {
  let mp = 0;

  prices.forEach((price, index) => {
    mp += price * scales[index];
  });
  return Math.round(mp);
};

/**
 * @param {*} groupObj  {du: 123, ufo: 100, sj: 112}
 */
const calcPrice = (groupObj) => {
  const {ufo, sj, du} = groupObj;

  if (ufo && sj && du) {
    return mergePrice([ufo, sj, du], [0.5, 0.2, 0.3]);
  } else if (ufo && sj) {
    return mergePrice([ufo, sj], [0.7, 0.3]);
  } else if (ufo && du) {
    return mergePrice([ufo, du], [0.7, 0.3]);
  } else if (sj && du) {
    return mergePrice([sj, du], [0.5, 0.5]);
  } else {
    const onlyKey = Object.keys(groupObj).find(key => groupObj[key]);

    if (onlyKey) {
      return groupObj[onlyKey];
    }
  }
  return 0;
};

/**
 * @param {*} skuGroupObj {du: [{size: "37", price: 1999}], ufo: [{size: "37", price: 1999}] ...}
 * return {'37': {du: 123, ufo: 100, sj: 112}}
 */
const mergeSkus = (skuGroupObj) => {
  const mergeGroups = {};

  _.each(skuGroupObj, (skus, key) => {
    if (skus) {
      _.each(skus, sku => {
        if (!mergeGroups[sku.size]) {
          mergeGroups[sku.size] = {};
        }
        mergeGroups[sku.size][key] = sku.price;
      });
    }
  });
  return mergeGroups;
};

const task = async({productId, productCode, third}) => {
  try {
    const results = await Promise.all([
      spiderUfo(third.ufo),
      spiderSj(third.sj, productCode, sizeRelation),
      spiderDu(third.du),
    ]);
    const skusGroups = mergeSkus({
      ufo: _.get(results[0], 'skus', []),
      sj: _.get(results[1], 'skus', []),
      du: _.get(results[2], 'skus', []),
    });
    const skus = _.map(Object.keys(skusGroups), size => {
      if (sizeRelation[size]) {
        const price = calcPrice(skusGroups[size]);

        logger.info(`[price-day-task] skusGroups: ${JSON.stringify(skusGroups[size])}, price: ${price}`);

        if (price > 0) {
          return {
            size,
            price,
            sizeId: _.get(sizeRelation[size], 'sizeId', 0)
          };
        }
      }
    }).filter(sku => sku);

    return {
      productId,
      price: Math.round(_.sumBy(skus, 'price') / skus.length) || 0,
      skus,
    };
  } catch (error) {
    logger.error(`[price-day-task] dayTask, ${error}`);
  }
};

const report = (product, time) => {
  _.forEach(product.skus, async(sku) => {
    const result = await mysqlPool.insert('INSERT INTO `price_trend_day` (`product_id`, `size_id`, `skn_price`, `sku_price`, `create_time`) VALUES (:productId, :sizeId, :sknPrice, :skuPrice, :createTime)', {
      productId: product.productId,
      sizeId: sku.sizeId,
      sknPrice: product.price,
      skuPrice: sku.price,
      createTime: time
    });


    if (result) {
      logger.info(`[price-day-task] dayTask, insert success productId: ${product.productId}, sizeId: ${sku.sizeId}, price: ${sku.price}, sknPrice: ${product.price}, time: ${time}`);
    } else {
      logger.error(`[price-day-task] dayTask, insert fail productId: ${product.productId}, sizeId: ${sku.sizeId}, price: ${sku.price}, sknPrice: ${product.price}, time: ${time}`);
    }
  });
};

module.exports = async() => {
  const now = dayjs().startOf('hour').unix();

  const resultExists = await mysqlPool.query('SELECT COUNT(*) AS Num FROM `price_trend_day` WHERE `create_time` = :createTime', {
    createTime: now
  });

  if (_.first(resultExists).Num > 0) {
    logger.info(`[price-day-task] dayTask, exists createtime price: ${now}`);
    return;
  }

  const lockTask = lockup(task);
  const products = await ProductRelationModel.findAll();

  products.forEach(async(product) => {
    const result = await lockTask(product);

    report(result, now);
  });
};