goods.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. 'use strict';
  2. const { CrudService } = require('naf-framework-mongoose-free/lib/service');
  3. const { BusinessError, ErrorCode } = require('naf-core').Error;
  4. const _ = require('lodash');
  5. const assert = require('assert');
  6. const { ObjectId } = require('mongoose').Types;
  7. //
  8. class GoodsService extends CrudService {
  9. constructor(ctx) {
  10. super(ctx, 'goods');
  11. this.goodsModel = this.ctx.model.Shop.Goods;
  12. this.goodsSpecModel = this.ctx.model.Shop.GoodsSpec;
  13. }
  14. /**
  15. *
  16. * @param {Object} query 查询条件
  17. * @param query.id 商品数据id
  18. */
  19. async goodsDetail({ id }) {
  20. // 添加宝贝数,商店3个评价
  21. const { populate } = this.ctx.service.shop.goods.getRefMods();
  22. let goods = await this.goodsModel.findById(id, { file: 1, tags: 1, name: 1, shot_brief: 1, brief: 1, send_time: 1, shop: 1, view_num: 1 }).populate(populate);
  23. if (!goods) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到商品数据');
  24. goods = JSON.parse(JSON.stringify(goods));
  25. let specs = await this.goodsSpecModel.find({ goods: id, status: '0' }, { sell_money: 1, flow_money: 1, freight: 1, name: 1, num: 1, can_group: 1, group_config: 1, file: 1 });
  26. specs = JSON.parse(JSON.stringify(specs));
  27. goods = _.omit(goods, [ 'meta', '__v' ]);
  28. const shop = _.pick(goods.shop, [ 'logo', 'name', 'person', 'phone', '_id', 'goods_score', 'send_score', 'service_score' ]);
  29. delete goods.shop;
  30. const goodsNum = await this.goodsModel.count({ shop, status: '1' });
  31. shop.goods_num = goodsNum;
  32. // goods: 商品信息; specs:商品规格信息; shop:店铺信息
  33. const returnData = { goods, specs, shop };
  34. // 添加浏览次数
  35. await this.goodsModel.updateOne({ _id: id }, { view_num: (goods.view_num || 0) + 1 });
  36. return returnData;
  37. }
  38. async indexGoodsList(condition, { skip = 0, limit = 20 } = {}) {
  39. condition = this.dealFilter(condition);
  40. const pipline = [{ $match: { status: { $ne: '0' } } }]; // { $sort: { sort: 1 } },
  41. const { view_num, sell_num, sell_money, name, shop, tags } = condition;
  42. let sort = {};
  43. if (view_num) sort.view_num = parseInt(view_num);
  44. if (sell_num) sort.sell_num = parseInt(sell_num);
  45. if (sell_money) sort.sell_money = parseInt(sell_money);
  46. if (name) pipline.push({ $match: { name: new RegExp(name) } });
  47. if (shop) pipline.push({ $match: { shop } });
  48. if (tags) pipline.push({ $match: { tags: { $elemMatch: { $elemMatch: { $eq: tags } } } } });
  49. pipline.push({ $addFields: { goods_id: { $toString: '$_id' }, create_time: { $dateToString: { date: '$meta.createdAt', format: '%Y-%m-%d %H:%M:%S', timezone: '+08:00' } } } });
  50. // 表关联
  51. pipline.push({
  52. $lookup: {
  53. from: 'goodsSpec',
  54. localField: 'goods_id',
  55. foreignField: 'goods',
  56. as: 'specs',
  57. },
  58. });
  59. // 按照规格平铺数据
  60. pipline.push({ $unwind: '$specs' });
  61. // 格式化平铺后的数据
  62. pipline.push({
  63. $project: {
  64. name: 1,
  65. view_num: 1,
  66. sell_num: 1,
  67. file: 1,
  68. sort: 1,
  69. create_time: 1,
  70. sell_money: { $toDouble: '$specs.sell_money' },
  71. flow_money: { $toDouble: '$specs.flow_money' },
  72. num: '$specs.num',
  73. },
  74. });
  75. pipline.push({
  76. $group: {
  77. _id: '$_id',
  78. data: { $min: '$$CURRENT' },
  79. },
  80. });
  81. pipline.push({
  82. $project: {
  83. name: '$data.name',
  84. view_num: '$data.view_num',
  85. sell_num: '$data.sell_num',
  86. file: '$data.file',
  87. sell_money: '$data.sell_money',
  88. flow_money: '$data.flow_money',
  89. num: '$data.num',
  90. create_time: '$data.create_time',
  91. sort: '$data.sort',
  92. },
  93. });
  94. if (Object.keys(sort).length <= 0) sort = { sort: -1, create_time: -1 };
  95. pipline.push({ $sort: { ...sort, sort: -1, create_time: -1 } });
  96. // 分页处理
  97. const qPipline = _.cloneDeep(pipline);
  98. if (parseInt(skip)) qPipline.push({ $skip: parseInt(skip) });
  99. if (parseInt(limit)) qPipline.push({ $limit: parseInt(limit) });
  100. let list = await this.goodsModel.aggregate(qPipline);
  101. list = list.map(i => {
  102. const obj = _.pick(i, [ 'name', 'file', 'num', 'flow_money', 'sell_money', 'view_num', '_id' ]);
  103. return obj;
  104. });
  105. const tPipline = _.cloneDeep(pipline);
  106. tPipline.push({ $count: 'total' });
  107. const total = await this.goodsModel.aggregate(tPipline);
  108. return { list, total: _.get(_.head(total), 'total', 0) };
  109. }
  110. async indexActTagsGoods() {
  111. // 将使用中且展示在首页的查出来排序
  112. const list = await this.ctx.model.System.ActTags.find({ status: '0', show_index: '0' }).sort({ sort: 1 });
  113. const result = [];
  114. for (const t of list) {
  115. const { label, value } = t;
  116. const list = await this.searchActTagsGoods(value);
  117. const arr = [];
  118. for (const g of list) {
  119. const obj = {
  120. url: _.get(g, 'file'),
  121. name: _.get(g, 'name'),
  122. id: _.get(g, '_id'),
  123. value,
  124. };
  125. if (arr.length === 0) {
  126. obj.title = label;
  127. }
  128. arr.push(obj);
  129. }
  130. result.push({ list: arr });
  131. }
  132. return result;
  133. }
  134. async searchActTagsGoods(act_tags, limit = 2) {
  135. const pipline = [{ $sort: { 'meta.createdAt': -1 } }, { $match: { status: { $ne: '0' }, act_tags } }];
  136. pipline.push({ $project: { name: 1, file: 1 } });
  137. if (parseInt(limit)) pipline.push({ $limit: parseInt(limit) });
  138. const list = await this.goodsModel.aggregate(pipline);
  139. return list;
  140. }
  141. }
  142. module.exports = GoodsService;