Ver Fonte

排序 搜索功能完成

maguohua há 8 anos atrás
pai
commit
aa4f0af33a

+ 50 - 0
InitData/activity.js

@@ -0,0 +1,50 @@
+export default [
+{
+description: "",
+icon_color: "3FBDE6",
+icon_name: "品",
+id: 8,
+name: "品牌商家",
+ranking_weight: 7
+},
+{
+description: "已加入“外卖保”计划,食品安全有保障",
+icon_color: "999999",
+icon_name: "保",
+id: 7,
+name: "外卖保",
+ranking_weight: 6
+},
+{
+description: "新店",
+icon_color: "E8842D",
+icon_name: "新",
+id: 5,
+name: "新店",
+ranking_weight: 4
+},
+{
+description: "该商家支持开发票,请在下单时填写好发票抬头",
+icon_color: "999999",
+icon_name: "票",
+id: 4,
+name: "开发票",
+ranking_weight: 3
+},
+{
+description: "可使用支付宝、微信、手机QQ进行在线支付",
+icon_color: "FF4E00",
+icon_name: "付",
+id: 3,
+name: "在线支付",
+ranking_weight: 2
+},
+{
+description: "准时必达,超时秒赔",
+icon_color: "57A9FF",
+icon_name: "准",
+id: 9,
+name: "准时达",
+ranking_weight: 1
+}
+]

+ 6 - 0
InitData/delivery.js

@@ -0,0 +1,6 @@
+export default {
+color: "57A9FF",
+id: 1,
+is_solid: true,
+text: "蜂鸟专送"
+}

+ 3 - 3
README.md

@@ -1,6 +1,6 @@
 # Project
 
-此项目是前端项目 [vue2-elm](https://github.com/bailicangdu/vue2-elm) 的后台系统,保持和官网一致的API接口。并提供一个对应的后台管理系统 [vue2-manage](https://github.com/bailicangdu/back-manage) 。
+此项目是前端项目 [vue2-elm](https://github.com/bailicangdu/vue2-elm) 的后台系统,保持和官网一致的API接口。并具有对应的后台管理系统 [vue2-manage](https://github.com/bailicangdu/back-manage) 。
 
 
 
@@ -52,8 +52,8 @@ npm run dev
 - [x] 添加商铺
 - [x] 添加食品
 - [x] 测距
-- [ ] 搜索美食,餐馆
-- [ ] 餐馆排序
+- [x] 搜索美食,餐馆
+- [x] 餐馆排序
 - [ ] 购物车功能
 - [ ] 评价
 - [ ] 食品详情

+ 1 - 1
app.js

@@ -65,7 +65,7 @@ router(app);
 // }));
 
 app.use((err, req, res, next) => {
-	res.send('未找到当前路由');
+	res.status(404).send('未找到当前路由');
 });
 
 

+ 45 - 0
controller/shopping/category.js

@@ -2,6 +2,8 @@
 
 import CategoryModel from '../../models/shopping/category'
 import BaseComponent from '../../prototype/baseComponent'
+import DeliveryModel from '../../models/shopping/delivery'
+import ActivityModel from '../../models/shopping/activity'
 
 class Category extends BaseComponent{
 	constructor(){
@@ -28,6 +30,49 @@ class Category extends BaseComponent{
 			console.log('增加category数量失败');
 		}
 	}
+	async findById(id){
+		try{
+			const CateEntity = await CategoryModel.findOne({'sub_categories.id': id});
+			let categoName = CateEntity.name;
+			CateEntity.sub_categories.forEach(item => {
+				if (item.id == id) {
+					categoName += '/' + item.name;
+				}
+			})
+			return categoName
+		}catch(err){
+			console.log('通过category id获取数据失败')
+			throw new Error(err)
+		}
+	}
+	//获取配送方式
+	async getDelivery(req, res, next){
+		try{
+			const deliveries = await DeliveryModel.find({}, '-_id');
+			res.send(deliveries)
+		}catch(err){
+			console.log('获取配送方式数据失败');
+			res.send({
+				status: 0,
+				type: 'ERROR_DATA',
+				message: '获取配送方式数据失败'
+			})
+		}
+	}
+	//获取活动列表
+	async getActivity(req, res, next){
+		try{
+			const activities = await ActivityModel.find({}, '-_id');
+			res.send(activities)
+		}catch(err){
+			console.log('获取活动数据失败');
+			res.send({
+				status: 0,
+				type: 'ERROR_DATA',
+				message: '获取活动数据失败'
+			})
+		}
+	}
 }
 
 export default new Category()

+ 0 - 55
controller/shopping/food.js

@@ -258,61 +258,6 @@ class Food extends BaseComponent{
 				})
 			}
 		})
-		const aa = 
-		{
-			description: "大家喜欢吃,才叫真好吃。",
-			is_selected: true,
-			icon_url: "5da3872d782f707b4c82ce4607c73d1ajpeg",
-			name: "热销榜",
-			id: 1,
-			restaurant_id: 3,
-			foods: [
-				{
-					name: "招牌豪大大鸡排(特大)",
-					description: "",
-					image_path: "8c4faa8342498a301c464711b6d8a8bcjpeg",
-					activity: null,
-					attributes: [ ],
-					restaurant_id: 154078098,
-					category_id: 513873481,
-					satisfy_rate: 93,
-					satisfy_count: 80,
-					item_id: "165472716078",
-					rating: 4.3,
-					rating_count: 86,
-					month_sales: 262,
-					tips: "86评价 月售262份",
-					specfoods: [
-						{
-							packing_fee: 0,
-							price: 16,
-							specs: [
-								{
-									name: "规格",
-									value: "招牌豪大大鸡排(特大)"
-								}
-							],
-							name: "招牌豪大大鸡排(特大)",
-							item_id: "165472716078",
-							sku_id: "191809493294",
-							food_id: 577587396,
-							restaurant_id: 154078098,
-							recent_rating: 4.3,
-							recent_popularity: 131,
-						},
-					],
-					specifications: [
-						{
-							values: [
-								"招牌豪大大鸡排(特大)",
-								"默认"
-							],
-							name: "规格"
-						}
-					],
-				}
-			]
-		}
 	}
 }
 

+ 116 - 7
controller/shopping/shop.js

@@ -10,7 +10,9 @@ class Shop extends AddressComponent{
 		super()
 		this.addShop = this.addShop.bind(this);
 		this.getRestaurants = this.getRestaurants.bind(this);
+		this.searchResaturant = this.searchResaturant.bind(this);
 	}
+	//添加商铺
 	async addShop(req, res, next){
 		let restaurant_id;
 		try{
@@ -58,6 +60,7 @@ class Shop extends AddressComponent{
 				is_new: fields.new || false,
 				latitude: fields.latitude,
 				longitude: fields.longitude,
+				location: [fields.longitude, fields.latitude],
 				opening_hours: [opening_hours],
 				phone: fields.phone,
 				promotion_info: fields.promotion_info || "欢迎光临,用餐高峰请提前下单,谢谢",
@@ -89,6 +92,7 @@ class Shop extends AddressComponent{
 					registered_number: "",
 				},
 			}
+			//配送方式
 			if (fields.delivery_mode) {
 				Object.assign(newShop, {delivery_mode: {
 					color: "57A9FF",
@@ -97,6 +101,7 @@ class Shop extends AddressComponent{
 					text: "蜂鸟专送"
 				}})
 			}
+			//商店支持的活动
 			fields.activities.forEach((item, index) => {
 				switch(item.icon_name){
 					case '减': 
@@ -146,6 +151,7 @@ class Shop extends AddressComponent{
 				})
 			}
 			try{
+				//保存数据,并增加对应食品种类的数量
 				const shop = new ShopModel(newShop);
 				await shop.save();
 				CategoryHandle.addCategory(fields.category)
@@ -174,9 +180,11 @@ class Shop extends AddressComponent{
 			restaurant_category_id,
 			order_by,
 			extras,
-			delivery_mode,
-			restaurant_category_ids,
+			delivery_mode = [],
+			support_ids = [],
+			restaurant_category_ids = [],
 		} = req.query;
+
 		try{
 			if (!latitude) {
 				throw new Error('latitude参数错误')
@@ -192,18 +200,73 @@ class Shop extends AddressComponent{
 			})
 			return
 		}
-		const restaurants = await ShopModel.find({}, '-_id').limit(Number(limit)).skip(Number(offset));
+		let filter = {};
+		//获取对应食品种类
+		if (restaurant_category_ids.length && Number(restaurant_category_ids[0])) {
+			const category =  await CategoryHandle.findById(restaurant_category_ids[0]);
+			Object.assign(filter, {category})
+		}
+		//按照距离,评分,销量等排序
+		let sortBy = {}
+		if (Number(order_by)) {
+			switch(Number(order_by)){
+				case 1:
+					Object.assign(sortBy, {float_minimum_order_amount: 1});
+					break;
+				case 2:
+					Object.assign(filter, {location: {$near: [longitude, latitude]}});
+					break;
+				case 3:
+					Object.assign(sortBy, {rating: -1});
+					break;
+				case 5:
+					Object.assign(filter, {location: {$near: [longitude, latitude]}});
+					break;
+				case 6:
+					Object.assign(sortBy, {recent_order_num: -1});
+					break;
+			}
+		}
+		//查找配送方式
+		if (delivery_mode.length) {
+			delivery_mode.forEach(item => {
+				if (Number(item)) {
+					Object.assign(filter, {'delivery_mode.id': Number(item)})
+				}
+			})
+		}
+		//查找活动支持方式
+		if (support_ids.length) {
+			const filterArr = []; 
+			support_ids.forEach(item => {
+				if (Number(item) && (Number(item) !== 8)) {
+					filterArr.push(Number(item))
+				}else if(Number(item) == 8){ //品牌保证特殊处理
+					Object.assign(filter, {is_premium: true})
+				}
+			})
+			if (filterArr.length) {
+				//匹配同时拥有多种活动的数据
+				Object.assign(filter, {'supports.id': {$all: filterArr}})
+			}
+		}
+
+		const restaurants = await ShopModel.find(filter, '-_id').sort(sortBy).limit(Number(limit)).skip(Number(offset))
 		const from = latitude + ',' + longitude;
 		let to = '';
+		//获取百度地图测局所需经度纬度
 		restaurants.forEach((item, index) => {
 			const slpitStr = (index == restaurants.length -1) ? '' : '|';
 			to += item.latitude + ',' + item.longitude + slpitStr;
 		})
 		try{
-			const positionArr = await this.getDistance(from, to)
-			restaurants.map((item, index) => {
-				return Object.assign(item, positionArr[index])
-			})
+			if (restaurants.length) {
+				//获取距离信息,并合并到数据中
+				const distance_duration = await this.getDistance(from, to)
+				restaurants.map((item, index) => {
+					return Object.assign(item, distance_duration[index])
+				})
+			}
 			res.send(restaurants)
 		}catch(err){
 			console.log('从addressComoponent获取数据后处理失败');
@@ -214,6 +277,52 @@ class Shop extends AddressComponent{
 			})
 		}
 	}
+	//搜索餐馆
+	async searchResaturant(req, res, next){
+		const {geohash, keyword} = req.query;
+		try{
+			if (!geohash || geohash.indexOf(',') == -1) {
+				throw new Error('经纬度参数错误');
+			}else if(!keyword){
+				throw new Error('关键词参数错误');
+			}
+		}catch(err){
+			console.log('搜索商铺参数错误');
+			res.send({
+				status: 0,
+				type: 'ERROR_PARAMS',
+				message: err.message,
+			})
+			return
+		}
+		
+		try{
+			const restaurants = await ShopModel.find({name: eval('/' + keyword + '/gi')}, '-_id').limit(50);
+			if (restaurants.length) {
+				const [latitude, longitude] = geohash.split(',');
+				const from = latitude + ',' + longitude;
+				let to = '';
+				//获取百度地图测局所需经度纬度
+				restaurants.forEach((item, index) => {
+					const slpitStr = (index == restaurants.length -1) ? '' : '|';
+					to += item.latitude + ',' + item.longitude + slpitStr;
+				})
+				//获取距离信息,并合并到数据中
+				const distance_duration = await this.getDistance(from, to)
+				restaurants.map((item, index) => {
+					return Object.assign(item, distance_duration[index])
+				})
+			}
+			res.send(restaurants);
+		}catch(err){
+			console.log('搜索餐馆数据失败');
+			res.send({
+				status: 0,
+				type: 'ERROR_DATA',
+				message: '搜索餐馆数据失败'
+			})
+		}
+	}
 }
 
 export default new Shop()

+ 29 - 0
models/shopping/activity.js

@@ -0,0 +1,29 @@
+'use strict';
+
+import mongoose from 'mongoose'
+import activityData from '../../InitData/activity'
+
+const Schema = mongoose.Schema;
+
+const activitySchema = new Schema({
+	description: String,
+	icon_color: String,
+	icon_name: String,
+	id: Number,
+	name: String,
+	ranking_weight: Number
+})
+
+activitySchema.index({index: 1});
+
+const Activity = mongoose.model('Activity', activitySchema);
+
+Activity.findOne((err, data) => {
+	if (!data) {
+		activityData.forEach(item => {
+			Activity.create(item);
+		})
+	}
+})
+
+export default Activity

+ 1 - 1
models/shopping/category.js

@@ -41,7 +41,7 @@ categorySchema.statics.addCategory = async function (type){
 		return
 	}catch(err){
 		console.log('保存cetegroy失败');
-		throw new Error('保存cetegroy失败')
+		throw new Error(err)
 	}
 }
 

+ 25 - 0
models/shopping/delivery.js

@@ -0,0 +1,25 @@
+'use strict';
+
+import mongoose from 'mongoose'
+import deliveryData from '../../InitData/delivery'
+
+const Schema = mongoose.Schema;
+
+const DeliverySchema = new Schema({
+	color: String,
+	id: Number,
+	is_solid: Boolean,
+	text: String
+})
+
+DeliverySchema.index({id: 1});
+
+const Delivery = mongoose.model('Delivery', DeliverySchema);
+
+Delivery.findOne((err, data) => {
+	if (!data) {
+		Delivery.create(deliveryData);
+	}
+})
+
+export default Delivery

+ 1 - 0
models/shopping/shop.js

@@ -20,6 +20,7 @@ const shopSchema = new mongoose.Schema({
 	description: { type: String, default: "" },
 	order_lead_time: { type: String, default: "" },
 	distance: { type: String, default: "" },
+	location:{type:[Number],index: '2d'},
 	float_delivery_fee: { type: Number, default: 0 },
 	float_minimum_order_amount: { type: Number, default: 0 },
 	id: Number,

+ 14 - 9
prototype/addressComponent.js

@@ -37,7 +37,7 @@ class AddressComponent extends BaseComponent {
 	 			return cityInfo
 	 		}else{
 	 			console.log('定位失败');
-	 			throw new Error('定位失败');
+	 			throw new Error(err);
 	 		}
  			
  		}catch(err){
@@ -57,7 +57,7 @@ class AddressComponent extends BaseComponent {
 				return resObj
 			}else{
 				console.log('搜索位置信息失败')
-				throw new Error('搜索位置信息失败');
+				throw new Error(err);
 			}
 		}catch(err){
 			throw new Error(err);
@@ -75,19 +75,24 @@ class AddressComponent extends BaseComponent {
 			if(res.status == 0){
 				const positionArr = []; 
 				res.result.forEach(item => {
+					const timevalue = parseInt(item.duration.value) + 1200;
+					let durationtime = Math.ceil(timevalue%3600/60) + '分钟';
+					if(Math.floor(timevalue/3600)){
+						durationtime = Math.floor(timevalue/3600) + '小时' + durationtime;
+					}
 					positionArr.push({
 						distance: item.distance.text,
-						order_lead_time: item.duration.text,
+						order_lead_time: durationtime,
 					})
 				})
 				return positionArr
 			}else{
 				console.log('调用百度地图测距失败');
-				throw new Error('调用百度地图测距失败');
+				throw new Error(err);
 			}
 		}catch(err){
 			console.log('获取位置距离失败')
-			throw new Error('获取位置距离失败');
+			throw new Error(err);
 		}
 	}
 	//通过ip地址获取精确位置
@@ -102,11 +107,11 @@ class AddressComponent extends BaseComponent {
 				return res
 			}else{
 				console.log('获取具体位置信息失败');
-				throw new Error('获取具体位置信息失败');
+				throw new Error(err);
 			}
 		}catch(err){
 			console.log('geocoder获取定位失败')
-			throw new Error('geocoder获取定位失败');
+			throw new Error(err);
 		}
 	}
 	//通过geohash获取精确位置
@@ -120,11 +125,11 @@ class AddressComponent extends BaseComponent {
 				return res
 			}else{
 				console.log('通过获geohash取具体位置失败');
-				throw new Error('通过geohash获取具体位置失败');
+				throw new Error(err);
 			}
 		}catch(err){
 			console.log('getpois获取定位失败')
-			throw new Error('getpois获取定位失败');
+			throw new Error(err);
 		}
 	}
 }

+ 2 - 0
routes/index.js

@@ -3,6 +3,7 @@
 import home from './home';
 import v1 from './v1'
 import v2 from './v2'
+import v4 from './v4'
 import shopping from './shopping'
 
 export default app => {
@@ -12,5 +13,6 @@ export default app => {
 	app.use('/home', home);
 	app.use('/v1', v1);
 	app.use('/v2', v2);
+	app.use('/v4', v4);
 	app.use('/shopping', shopping);
 }

+ 2 - 0
routes/shopping.js

@@ -15,5 +15,7 @@ router.post('/addfood', Food.addFood);
 router.get('/getcategory/:restaurant_id', Food.getCategory);
 router.post('/addcategory', Food.addCategory);
 router.get('/v2/restaurant/category', Category.getCategories);
+router.get('/v1/restaurants/delivery_modes', Category.getDelivery);
+router.get('/v1/restaurants/activity_attributes', Category.getActivity);
 
 export default router

+ 6 - 1
routes/v4.js

@@ -1,4 +1,9 @@
 'use strict';
 
 import express from 'express';
-const router = express.Router();
+import Food from '../controller/shopping/shop'
+const router = express.Router();
+
+router.get('/restaurants', Food.searchResaturant);
+
+export default router