shop.js 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. 'use strict';
  2. import ShopModel from '../../models/shopping/shop'
  3. import AddressComponent from '../../prototype/addressComponent'
  4. import Food from './food'
  5. import formidable from 'formidable'
  6. import CategoryHandle from './category'
  7. import Rating from '../ugc/rating'
  8. class Shop extends AddressComponent{
  9. constructor(){
  10. super()
  11. this.addShop = this.addShop.bind(this);
  12. this.getRestaurants = this.getRestaurants.bind(this);
  13. this.searchResaturant = this.searchResaturant.bind(this);
  14. }
  15. //添加商铺
  16. async addShop(req, res, next){
  17. let restaurant_id;
  18. try{
  19. restaurant_id = await this.getId('restaurant_id');
  20. }catch(err){
  21. console.log('获取商店id失败');
  22. res.send({
  23. type: 'ERROR_DATA',
  24. message: '获取数据失败'
  25. })
  26. return
  27. }
  28. const form = new formidable.IncomingForm();
  29. form.parse(req, async (err, fields, files) => {
  30. try{
  31. if (!fields.name) {
  32. throw new Error('必须填写商店名称');
  33. }else if(!fields.address){
  34. throw new Error('必须填写商店地址');
  35. }else if(!fields.phone){
  36. throw new Error('必须填写联系电话');
  37. }else if(!fields.latitude || !fields.longitude){
  38. throw new Error('商店位置信息错误');
  39. }else if(!fields.image_path){
  40. throw new Error('必须上传商铺图片');
  41. }else if(!fields.category){
  42. throw new Error('必须上传食品种类');
  43. }
  44. }catch(err){
  45. console.log('前台参数出错');
  46. res.send({
  47. status: 0,
  48. type: 'ERROR_PARAMS',
  49. message: err.message
  50. })
  51. return
  52. }
  53. const opening_hours = fields.startTime&&fields.endTime? fields.startTime + '/' + fields.endTime : "8:30/20:30";
  54. const newShop = {
  55. name: fields.name,
  56. address: fields.address,
  57. description: fields.description || '',
  58. float_delivery_fee: fields.float_delivery_fee || 0,
  59. float_minimum_order_amount: fields.float_minimum_order_amount || 0,
  60. id: restaurant_id,
  61. is_premium: fields.is_premium || false,
  62. is_new: fields.new || false,
  63. latitude: fields.latitude,
  64. longitude: fields.longitude,
  65. location: [fields.longitude, fields.latitude],
  66. opening_hours: [opening_hours],
  67. phone: fields.phone,
  68. promotion_info: fields.promotion_info || "欢迎光临,用餐高峰请提前下单,谢谢",
  69. rating: (Math.random()*5).toFixed(1),
  70. rating_count: Math.ceil(Math.random()*1000),
  71. recent_order_num: Math.ceil(Math.random()*1000),
  72. status: Math.round(Math.random()),
  73. image_path: fields.image_path,
  74. category: fields.category,
  75. piecewise_agent_fee: {
  76. tips: "配送费约¥" + (fields.float_delivery_fee || 0),
  77. },
  78. activities: [],
  79. supports: [],
  80. license: {
  81. business_license_image: fields.business_license_image || '',
  82. catering_service_license_image: fields.catering_service_license_image || '',
  83. },
  84. identification: {
  85. company_name: "",
  86. identificate_agency: "",
  87. identificate_date: "",
  88. legal_person: "",
  89. licenses_date: "",
  90. licenses_number: "",
  91. licenses_scope: "",
  92. operation_period: "",
  93. registered_address: "",
  94. registered_number: "",
  95. },
  96. }
  97. //配送方式
  98. if (fields.delivery_mode) {
  99. Object.assign(newShop, {delivery_mode: {
  100. color: "57A9FF",
  101. id: 1,
  102. is_solid: true,
  103. text: "蜂鸟专送"
  104. }})
  105. }
  106. //商店支持的活动
  107. fields.activities.forEach((item, index) => {
  108. switch(item.icon_name){
  109. case '减':
  110. item.icon_color = 'f07373';
  111. item.id = index + 1;
  112. break;
  113. case '特':
  114. item.icon_color = 'EDC123';
  115. item.id = index + 1;
  116. break;
  117. case '新':
  118. item.icon_color = '70bc46';
  119. item.id = index + 1;
  120. break;
  121. case '领':
  122. item.icon_color = 'E3EE0D';
  123. item.id = index + 1;
  124. break;
  125. }
  126. newShop.activities.push(item);
  127. })
  128. if (fields.bao) {
  129. newShop.supports.push({
  130. description: "已加入“外卖保”计划,食品安全有保障",
  131. icon_color: "999999",
  132. icon_name: "保",
  133. id: 7,
  134. name: "外卖保"
  135. })
  136. }
  137. if (fields.zhun) {
  138. newShop.supports.push({
  139. description: "准时必达,超时秒赔",
  140. icon_color: "57A9FF",
  141. icon_name: "准",
  142. id: 9,
  143. name: "准时达"
  144. })
  145. }
  146. if (fields.piao) {
  147. newShop.supports.push({
  148. description: "该商家支持开发票,请在下单时填写好发票抬头",
  149. icon_color: "999999",
  150. icon_name: "票",
  151. id: 4,
  152. name: "开发票"
  153. })
  154. }
  155. try{
  156. //保存数据,并增加对应食品种类的数量
  157. const shop = new ShopModel(newShop);
  158. await shop.save();
  159. CategoryHandle.addCategory(fields.category)
  160. Rating.initData(restaurant_id);
  161. Food.initData(restaurant_id);
  162. res.send({
  163. status: 1,
  164. sussess: '添加餐馆成功',
  165. shopDetail: newShop
  166. })
  167. }catch(err){
  168. console.log('商铺写入数据库失败');
  169. res.send({
  170. status: 0,
  171. type: 'ERROR_SERVER',
  172. message: '添加商铺失败',
  173. })
  174. }
  175. })
  176. }
  177. //获取餐馆列表
  178. async getRestaurants(req, res, next){
  179. const {
  180. latitude,
  181. longitude,
  182. offset = 0,
  183. limit = 20,
  184. keyword,
  185. restaurant_category_id,
  186. order_by,
  187. extras,
  188. delivery_mode = [],
  189. support_ids = [],
  190. restaurant_category_ids = [],
  191. } = req.query;
  192. try{
  193. if (!latitude) {
  194. throw new Error('latitude参数错误')
  195. }else if(!longitude){
  196. throw new Error('longitude参数错误');
  197. }
  198. }catch(err){
  199. console.log('latitude,longitude参数错误');
  200. res.send({
  201. status: 0,
  202. type: 'ERROR_PARAMS',
  203. message: err.message
  204. })
  205. return
  206. }
  207. let filter = {};
  208. //获取对应食品种类
  209. if (restaurant_category_ids.length && Number(restaurant_category_ids[0])) {
  210. const category = await CategoryHandle.findById(restaurant_category_ids[0]);
  211. Object.assign(filter, {category})
  212. }
  213. //按照距离,评分,销量等排序
  214. let sortBy = {}
  215. if (Number(order_by)) {
  216. switch(Number(order_by)){
  217. case 1:
  218. Object.assign(sortBy, {float_minimum_order_amount: 1});
  219. break;
  220. case 2:
  221. Object.assign(filter, {location: {$near: [longitude, latitude]}});
  222. break;
  223. case 3:
  224. Object.assign(sortBy, {rating: -1});
  225. break;
  226. case 5:
  227. Object.assign(filter, {location: {$near: [longitude, latitude]}});
  228. break;
  229. case 6:
  230. Object.assign(sortBy, {recent_order_num: -1});
  231. break;
  232. }
  233. }
  234. //查找配送方式
  235. if (delivery_mode.length) {
  236. delivery_mode.forEach(item => {
  237. if (Number(item)) {
  238. Object.assign(filter, {'delivery_mode.id': Number(item)})
  239. }
  240. })
  241. }
  242. //查找活动支持方式
  243. if (support_ids.length) {
  244. const filterArr = [];
  245. support_ids.forEach(item => {
  246. if (Number(item) && (Number(item) !== 8)) {
  247. filterArr.push(Number(item))
  248. }else if(Number(item) == 8){ //品牌保证特殊处理
  249. Object.assign(filter, {is_premium: true})
  250. }
  251. })
  252. if (filterArr.length) {
  253. //匹配同时拥有多种活动的数据
  254. Object.assign(filter, {'supports.id': {$all: filterArr}})
  255. }
  256. }
  257. const restaurants = await ShopModel.find(filter, '-_id').sort(sortBy).limit(Number(limit)).skip(Number(offset))
  258. const from = latitude + ',' + longitude;
  259. let to = '';
  260. //获取百度地图测局所需经度纬度
  261. restaurants.forEach((item, index) => {
  262. const slpitStr = (index == restaurants.length -1) ? '' : '|';
  263. to += item.latitude + ',' + item.longitude + slpitStr;
  264. })
  265. try{
  266. if (restaurants.length) {
  267. //获取距离信息,并合并到数据中
  268. const distance_duration = await this.getDistance(from, to)
  269. restaurants.map((item, index) => {
  270. return Object.assign(item, distance_duration[index])
  271. })
  272. }
  273. res.send(restaurants)
  274. }catch(err){
  275. console.log('从addressComoponent获取数据后处理失败');
  276. res.send({
  277. status: 0,
  278. type: 'ERROR_DATA',
  279. message: '获取数据失败'
  280. })
  281. }
  282. }
  283. //搜索餐馆
  284. async searchResaturant(req, res, next){
  285. const {geohash, keyword} = req.query;
  286. try{
  287. if (!geohash || geohash.indexOf(',') == -1) {
  288. throw new Error('经纬度参数错误');
  289. }else if(!keyword){
  290. throw new Error('关键词参数错误');
  291. }
  292. }catch(err){
  293. console.log('搜索商铺参数错误');
  294. res.send({
  295. status: 0,
  296. type: 'ERROR_PARAMS',
  297. message: err.message,
  298. })
  299. return
  300. }
  301. try{
  302. const restaurants = await ShopModel.find({name: eval('/' + keyword + '/gi')}, '-_id').limit(50);
  303. if (restaurants.length) {
  304. const [latitude, longitude] = geohash.split(',');
  305. const from = latitude + ',' + longitude;
  306. let to = '';
  307. //获取百度地图测局所需经度纬度
  308. restaurants.forEach((item, index) => {
  309. const slpitStr = (index == restaurants.length -1) ? '' : '|';
  310. to += item.latitude + ',' + item.longitude + slpitStr;
  311. })
  312. //获取距离信息,并合并到数据中
  313. const distance_duration = await this.getDistance(from, to)
  314. restaurants.map((item, index) => {
  315. return Object.assign(item, distance_duration[index])
  316. })
  317. }
  318. res.send(restaurants);
  319. }catch(err){
  320. console.log('搜索餐馆数据失败');
  321. res.send({
  322. status: 0,
  323. type: 'ERROR_DATA',
  324. message: '搜索餐馆数据失败'
  325. })
  326. }
  327. }
  328. //获取餐馆详情
  329. async getRestaurantDetail(req, res, next){
  330. const restaurant_id = req.params.restaurant_id;
  331. if (!restaurant_id || !Number(restaurant_id)) {
  332. console.log('获取餐馆详情参数ID错误');
  333. res.send({
  334. status: 0,
  335. type: 'ERROR_PARAMS',
  336. message: '餐馆ID参数错误',
  337. })
  338. return
  339. }
  340. try{
  341. const restaurant = await ShopModel.findOne({id: restaurant_id}, '-_id');
  342. res.send(restaurant)
  343. }catch(err){
  344. console.log('获取餐馆详情失败', err);
  345. res.send({
  346. status: 0,
  347. type: 'GET_DATA_ERROR',
  348. message: '获取餐馆详情失败'
  349. })
  350. }
  351. }
  352. }
  353. export default new Shop()