'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; this.gjaModel = this.ctx.model.Shop.GoodsJoinAct; this.goodsTagsModel = this.ctx.model.System.GoodsTags; } /** * * @param {Object} query 查询条件 * @param query.id 商品数据id */ async goodsDetail({ id }) { assert(id, '缺少商品信息'); const pipeline = [{ $match: { _id: ObjectId(id) } }]; const goodsProject = { file: 1, tags: 1, name: 1, shot_brief: 1, brief: 1, send_time: 1, shop: 1, view_num: 1, act_tags: 1 }; // 将 活动标签都进行数据替换 pipeline.push({ $lookup: { from: 'actTags', localField: 'act_tags', foreignField: 'value', pipeline: [{ $project: { label: 1 } }], as: 'act_tags', }, }); // 找店铺信息 pipeline.push({ $addFields: { shop_id: { $toObjectId: '$shop' } } }); pipeline.push({ $lookup: { from: 'shop', localField: 'shop_id', foreignField: '_id', pipeline: [ { $addFields: { shop_id: { $toString: '$_id' } } }, // 计算店铺商品总数 { $lookup: { from: 'goods', localField: 'shop_id', foreignField: 'shop', pipeline: [{ $match: { status: '1' } }, { $count: 'gn' }], as: 'gn', }, }, { $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' } } }, ], as: 'shopInfo', }, }); pipeline.push({ $project: { ...goodsProject, shopInfo: { $first: '$shopInfo' } } }); // 找规格 pipeline.push({ $addFields: { goods_id: { $toString: '$_id' } } }); pipeline.push({ $lookup: { from: 'goodsSpec', localField: 'goods_id', foreignField: 'goods', pipeline: [ { $project: { sell_money: { $toDouble: '$sell_money' }, flow_money: { $toDouble: '$flow_money' }, freight: { $toDouble: '$freight' }, name: 1, num: 1, can_group: 1, group_config: 1, file: 1, }, }, ], as: 'specs', }, }); pipeline.push({ $project: { ...goodsProject, goods_id: 1, specs: 1, shopInfo: 1 } }); // 找到商品是否参与活动,且该活动是否正在进行 pipeline.push({ $lookup: { from: 'goodsJoinAct', localField: 'goods_id', foreignField: 'goods._id', pipeline: [ { $addFields: { pa: { $toObjectId: '$platform_act' } } }, { $lookup: { from: 'platformAct', localField: 'pa', foreignField: '_id', pipeline: [{ $match: { is_use: '0' } }], as: 'act', }, }, { $unwind: '$act' }, { $replaceRoot: { newRoot: '$act' } }, { $project: { act_time: 1, config: 1, type: 1 } }, ], as: 'act', }, }); // // 整理数据 pipeline.push({ $project: { _id: 0, goods: { _id: '$$CURRENT._id', brief: '$$CURRENT.brief', file: '$$CURRENT.file', name: '$$CURRENT.name', send_time: '$$CURRENT.send_time', tags: '$$CURRENT.tags', act_tags: '$$CURRENT.act_tags', shot_brief: '$$CURRENT.shot_brief', view_num: '$$CURRENT.view_num', }, shop: '$shopInfo', specs: '$specs', act: '$act', }, }); const res = await this.goodsModel.aggregate(pipeline); let data = _.head(res); if (data) data = JSON.parse(JSON.stringify(data)); if (data.goods.tags.length > 0) { const nt = []; for (const t of data.goods.tags) { const code = _.last(t); const data = await this.goodsTagsModel.findOne({ code }, 'label'); nt.push(data); } data.goods.tags = nt; } for (const d of data.act) { const { tag, text } = this.ctx.service.system.platformAct.getActText(d); d.text = text; d.tag = tag; } return data; } async indexGoodsList(condition, { skip = 0, limit = 20 } = {}) { condition = this.dealFilter(condition); const pipeline = [{ $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) pipeline.push({ $match: { name: new RegExp(name) } }); if (shop) pipeline.push({ $match: { shop } }); if (tags) pipeline.push({ $match: { tags: { $elemMatch: { $elemMatch: { $eq: tags } } } } }); pipeline.push({ $lookup: { from: 'actTags', localField: 'act_tags', foreignField: 'value', pipeline: [ { $match: { status: '0', show_goods: '0' } }, { $sort: { sort: 1 } }, { $project: { label: 1, _id: 0 } }, ], as: 'actTagsShow', }, }); pipeline.push({ $addFields: { goods_id: { $toString: '$_id' }, create_time: { $dateToString: { date: '$meta.createdAt', format: '%Y-%m-%d %H:%M:%S', timezone: '+08:00' } } } }); // 表关联 pipeline.push({ $lookup: { from: 'goodsSpec', localField: 'goods_id', foreignField: 'goods', as: 'specs', }, }); // 按照规格平铺数据 pipeline.push({ $unwind: '$specs' }); // 格式化平铺后的数据 pipeline.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' }, num: '$specs.num', actTagsShow: 1, }, }); pipeline.push({ $group: { _id: '$_id', data: { $min: '$$CURRENT' }, }, }); pipeline.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', num: '$data.num', create_time: '$data.create_time', sort: '$data.sort', actTagsShow: '$data.actTagsShow', }, }); if (Object.keys(sort).length <= 0) sort = { sort: -1, create_time: -1 }; pipeline.push({ $sort: { ...sort, sort: -1, create_time: -1 } }); // 分页处理 const qpipeline = _.cloneDeep(pipeline); if (parseInt(skip)) qpipeline.push({ $skip: parseInt(skip) }); if (parseInt(limit)) qpipeline.push({ $limit: parseInt(limit) }); let list = await this.goodsModel.aggregate(qpipeline); list = list.map(i => { const obj = _.pick(i, [ 'name', 'file', 'num', 'flow_money', 'sell_money', 'view_num', '_id', 'actTagsShow' ]); return obj; }); const tpipeline = _.cloneDeep(pipeline); tpipeline.push({ $count: 'total' }); const total = await this.goodsModel.aggregate(tpipeline); 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 pipeline = [{ $sort: { 'meta.createdAt': -1 } }, { $match: { status: { $ne: '0' }, act_tags } }]; pipeline.push({ $project: { name: 1, file: 1 } }); if (parseInt(limit)) pipeline.push({ $limit: parseInt(limit) }); const list = await this.goodsModel.aggregate(pipeline); return list; } } module.exports = GoodsService;