shop.js 9.6 KB

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