goods.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  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. this.gjaModel = this.ctx.model.Shop.GoodsJoinAct;
  14. }
  15. /**
  16. *
  17. * @param {Object} query 查询条件
  18. * @param query.id 商品数据id
  19. */
  20. async goodsDetail({ id }) {
  21. assert(id, '缺少商品信息');
  22. const pipeline = [{ $match: { _id: ObjectId(id) } }];
  23. const goodsProject = { file: 1, tags: 1, name: 1, shot_brief: 1, brief: 1, send_time: 1, shop: 1, view_num: 1 };
  24. // 找店铺信息
  25. pipeline.push({ $addFields: { shop_id: { $toObjectId: '$shop' } } });
  26. pipeline.push({
  27. $lookup: {
  28. from: 'shop',
  29. localField: 'shop_id',
  30. foreignField: '_id',
  31. pipeline: [
  32. { $addFields: { shop_id: { $toString: '$_id' } } },
  33. // 计算店铺商品总数
  34. {
  35. $lookup: {
  36. from: 'goods',
  37. localField: 'shop_id',
  38. foreignField: 'shop',
  39. pipeline: [{ $match: { status: '1' } }, { $count: 'gn' }],
  40. as: 'gn',
  41. },
  42. },
  43. { $project: { logo: 1, name: 1, person: 1, phone: 1, _id: 1, goods_score: 1, send_score: 1, service_score: 1, goods_num: { $first: '$gn.gn' } } },
  44. ],
  45. as: 'shopInfo',
  46. },
  47. });
  48. pipeline.push({ $project: { ...goodsProject, shopInfo: { $first: '$shopInfo' } } });
  49. // 找规格
  50. pipeline.push({ $addFields: { goods_id: { $toString: '$_id' } } });
  51. pipeline.push({
  52. $lookup: {
  53. from: 'goodsSpec',
  54. localField: 'goods_id',
  55. foreignField: 'goods',
  56. pipeline: [
  57. {
  58. $project: {
  59. sell_money: { $toDouble: '$sell_money' },
  60. flow_money: { $toDouble: '$flow_money' },
  61. freight: { $toDouble: '$freight' },
  62. name: 1,
  63. num: 1,
  64. can_group: 1,
  65. group_config: 1,
  66. file: 1,
  67. },
  68. },
  69. ],
  70. as: 'specs',
  71. },
  72. });
  73. pipeline.push({ $project: { ...goodsProject, goods_id: 1, specs: 1, shopInfo: 1 } });
  74. // 找到商品是否参与活动,且该活动是否正在进行
  75. pipeline.push({
  76. $lookup: {
  77. from: 'goodsJoinAct',
  78. localField: 'goods_id',
  79. foreignField: 'goods._id',
  80. pipeline: [
  81. { $addFields: { pa: { $toObjectId: '$platform_act' } } },
  82. {
  83. $lookup: {
  84. from: 'platformAct',
  85. localField: 'pa',
  86. foreignField: '_id',
  87. pipeline: [{ $match: { is_use: '0' } }],
  88. as: 'act',
  89. },
  90. },
  91. { $unwind: '$act' },
  92. { $replaceRoot: { newRoot: '$act' } },
  93. { $project: { act_time: 1, config: 1, type: 1 } },
  94. ],
  95. as: 'act',
  96. },
  97. });
  98. // // 整理数据
  99. pipeline.push({
  100. $project: {
  101. _id: 0,
  102. goods: {
  103. _id: '$$CURRENT._id',
  104. brief: '$$CURRENT.brief',
  105. file: '$$CURRENT.file',
  106. name: '$$CURRENT.name',
  107. send_time: '$$CURRENT.send_time',
  108. tags: '$$CURRENT.tags',
  109. shot_brief: '$$CURRENT.shot_brief',
  110. view_num: '$$CURRENT.view_num',
  111. },
  112. shop: '$shopInfo',
  113. specs: '$specs',
  114. act: '$act',
  115. },
  116. });
  117. const res = await this.goodsModel.aggregate(pipeline);
  118. let data = _.head(res);
  119. if (data) data = JSON.parse(JSON.stringify(data));
  120. for (const d of data.act) {
  121. const { tag, text } = this.ctx.service.system.platformAct.getActText(d);
  122. d.text = text;
  123. d.tag = tag;
  124. }
  125. return data;
  126. }
  127. async indexGoodsList(condition, { skip = 0, limit = 20 } = {}) {
  128. condition = this.dealFilter(condition);
  129. const pipline = [{ $match: { status: { $ne: '0' } } }]; // { $sort: { sort: 1 } },
  130. const { view_num, sell_num, sell_money, name, shop, tags } = condition;
  131. let sort = {};
  132. if (view_num) sort.view_num = parseInt(view_num);
  133. if (sell_num) sort.sell_num = parseInt(sell_num);
  134. if (sell_money) sort.sell_money = parseInt(sell_money);
  135. if (name) pipline.push({ $match: { name: new RegExp(name) } });
  136. if (shop) pipline.push({ $match: { shop } });
  137. if (tags) pipline.push({ $match: { tags: { $elemMatch: { $elemMatch: { $eq: tags } } } } });
  138. pipline.push({ $addFields: { goods_id: { $toString: '$_id' }, create_time: { $dateToString: { date: '$meta.createdAt', format: '%Y-%m-%d %H:%M:%S', timezone: '+08:00' } } } });
  139. // 表关联
  140. pipline.push({
  141. $lookup: {
  142. from: 'goodsSpec',
  143. localField: 'goods_id',
  144. foreignField: 'goods',
  145. as: 'specs',
  146. },
  147. });
  148. // 按照规格平铺数据
  149. pipline.push({ $unwind: '$specs' });
  150. // 格式化平铺后的数据
  151. pipline.push({
  152. $project: {
  153. name: 1,
  154. view_num: 1,
  155. sell_num: 1,
  156. file: 1,
  157. sort: 1,
  158. create_time: 1,
  159. sell_money: { $toDouble: '$specs.sell_money' },
  160. flow_money: { $toDouble: '$specs.flow_money' },
  161. num: '$specs.num',
  162. },
  163. });
  164. pipline.push({
  165. $group: {
  166. _id: '$_id',
  167. data: { $min: '$$CURRENT' },
  168. },
  169. });
  170. pipline.push({
  171. $project: {
  172. name: '$data.name',
  173. view_num: '$data.view_num',
  174. sell_num: '$data.sell_num',
  175. file: '$data.file',
  176. sell_money: '$data.sell_money',
  177. flow_money: '$data.flow_money',
  178. num: '$data.num',
  179. create_time: '$data.create_time',
  180. sort: '$data.sort',
  181. },
  182. });
  183. if (Object.keys(sort).length <= 0) sort = { sort: -1, create_time: -1 };
  184. pipline.push({ $sort: { ...sort, sort: -1, create_time: -1 } });
  185. // 分页处理
  186. const qPipline = _.cloneDeep(pipline);
  187. if (parseInt(skip)) qPipline.push({ $skip: parseInt(skip) });
  188. if (parseInt(limit)) qPipline.push({ $limit: parseInt(limit) });
  189. let list = await this.goodsModel.aggregate(qPipline);
  190. list = list.map(i => {
  191. const obj = _.pick(i, [ 'name', 'file', 'num', 'flow_money', 'sell_money', 'view_num', '_id' ]);
  192. return obj;
  193. });
  194. const tPipline = _.cloneDeep(pipline);
  195. tPipline.push({ $count: 'total' });
  196. const total = await this.goodsModel.aggregate(tPipline);
  197. return { list, total: _.get(_.head(total), 'total', 0) };
  198. }
  199. async indexActTagsGoods() {
  200. // 将使用中且展示在首页的查出来排序
  201. const list = await this.ctx.model.System.ActTags.find({ status: '0', show_index: '0' }).sort({ sort: 1 });
  202. const result = [];
  203. for (const t of list) {
  204. const { label, value } = t;
  205. const list = await this.searchActTagsGoods(value);
  206. const arr = [];
  207. for (const g of list) {
  208. const obj = {
  209. url: _.get(g, 'file'),
  210. name: _.get(g, 'name'),
  211. id: _.get(g, '_id'),
  212. value,
  213. };
  214. if (arr.length === 0) {
  215. obj.title = label;
  216. }
  217. arr.push(obj);
  218. }
  219. result.push({ list: arr });
  220. }
  221. return result;
  222. }
  223. async searchActTagsGoods(act_tags, limit = 2) {
  224. const pipline = [{ $sort: { 'meta.createdAt': -1 } }, { $match: { status: { $ne: '0' }, act_tags } }];
  225. pipline.push({ $project: { name: 1, file: 1 } });
  226. if (parseInt(limit)) pipline.push({ $limit: parseInt(limit) });
  227. const list = await this.goodsModel.aggregate(pipline);
  228. return list;
  229. }
  230. }
  231. module.exports = GoodsService;