'use strict'; const { CrudService } = require('naf-framework-mongoose-free/lib/service'); const { BusinessError, ErrorCode } = require('naf-core').Error; const _ = require('lodash'); const assert = require('assert'); const { ObjectId } = require('mongoose').Types; // class GoodsService extends CrudService { constructor(ctx) { super(ctx, 'goods'); this.goodsModel = this.ctx.model.Shop.Goods; this.goodsSpecModel = this.ctx.model.Shop.GoodsSpec; } /** * * @param {Object} query 查询条件 * @param query.id 商品数据id */ async goodsDetail({ id }) { const { populate } = this.ctx.service.shop.goods.getRefMods(); 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); if (!goods) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到商品数据'); goods = JSON.parse(JSON.stringify(goods)); 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 }); specs = JSON.parse(JSON.stringify(specs)); goods = _.omit(goods, [ 'meta', '__v' ]); const shop = _.pick(goods.shop, [ 'logo', 'name', 'person', 'phone', '_id' ]); delete goods.shop; // 2022-10-17反馈问题6:将规格图片和商品图片合并,规格图片在前 for (const spec of specs) { if (_.isArray(spec.file)) { goods.file = [ ...spec.file, ..._.get(goods, 'file', []) ]; } } // goods: 商品信息; specs:商品规格信息; shop:店铺信息 const returnData = { goods, specs, shop }; // 添加浏览次数 await this.goodsModel.updateOne({ _id: id }, { view_num: (goods.view_num || 0) + 1 }); return returnData; } async indexGoodsList(condition, { skip = 0, limit = 20 } = {}) { condition = this.dealFilter(condition); const pipline = [{ $match: { status: { $ne: '0' } } }]; // { $sort: { sort: 1 } }, const { view_num, sell_num, sell_money, name, shop, tags } = condition; let sort = {}; if (view_num) sort.view_num = parseInt(view_num); if (sell_num) sort.sell_num = parseInt(sell_num); if (sell_money) sort.sell_money = parseInt(sell_money); if (name) pipline.push({ $match: { name: new RegExp(name) } }); if (shop) pipline.push({ $match: { shop } }); if (tags) pipline.push({ $match: { tags: { $elemMatch: { $elemMatch: { $eq: tags } } } } }); pipline.push({ $addFields: { goods_id: { $toString: '$_id' }, create_time: { $dateToString: { date: '$meta.createdAt', format: '%Y-%m-%d %H:%M:%S', timezone: '+08:00' } } } }); // 表关联 pipline.push({ $lookup: { from: 'goodsSpec', localField: 'goods_id', foreignField: 'goods', as: 'specs', }, }); // 按照规格平铺数据 pipline.push({ $unwind: '$specs' }); // 格式化平铺后的数据 // 2022-10-17反馈-问题6:将规格图片也拿出来 // TODO: 整理规格图片与正常的商品图片 pipline.push({ $project: { name: 1, view_num: 1, sell_num: 1, file: 1, sort: 1, create_time: 1, sell_money: { $toDouble: '$specs.sell_money' }, flow_money: { $toDouble: '$specs.flow_money' }, createdAt: '$meta.createdAt', spec_file: '$specs.file', }, }); pipline.push({ $group: { _id: '$_id', data: { $min: '$$CURRENT' }, }, }); pipline.push({ $project: { name: '$data.name', view_num: '$data.view_num', sell_num: '$data.sell_num', file: '$data.file', sell_money: '$data.sell_money', flow_money: '$data.flow_money', createdAt: '$data.createdAt', spec_file: '$data.spec_file', create_time: '$data.create_time', sort: '$data.sort', }, }); sort.sort = 1; sort = { ...sort, sort: 1, create_time: -1 }; pipline.push({ $sort: sort }); console.log(pipline); // 分页处理 const qPipline = _.cloneDeep(pipline); if (parseInt(skip)) qPipline.push({ $skip: parseInt(skip) }); if (parseInt(limit)) qPipline.push({ $limit: parseInt(limit) }); let list = await this.goodsModel.aggregate(qPipline); // 处理合并图片 list = list.map(i => { if (_.isArray(i.spec_file)) { i.file = [ ...i.spec_file, ...i.file ]; delete i.spec_file; } return i; }); const tPipline = _.cloneDeep(pipline); tPipline.push({ $count: 'total' }); const total = await this.goodsModel.aggregate(tPipline); return { list, total: _.get(_.head(total), 'total', 0) }; } async indexActTagsGoods() { // 将使用中且展示在首页的查出来排序 const list = await this.ctx.model.System.ActTags.find({ status: '0', show_index: '0' }).sort({ sort: 1 }); const result = []; for (const t of list) { const { label, value } = t; const list = await this.searchActTagsGoods(value); const arr = []; for (const g of list) { const obj = { url: _.get(g, 'file'), name: _.get(g, 'name'), id: _.get(g, '_id'), value, }; if (arr.length === 0) { obj.title = label; } arr.push(obj); } result.push({ list: arr }); } return result; } async searchActTagsGoods(act_tags, limit = 2) { const pipline = [{ $sort: { 'meta.createdAt': -1 } }, { $match: { status: { $ne: '0' }, act_tags } }]; pipline.push({ $project: { name: 1, file: 1 } }); if (parseInt(limit)) pipline.push({ $limit: parseInt(limit) }); const list = await this.goodsModel.aggregate(pipline); return list; } } module.exports = GoodsService;