├── .autod.conf.js
├── .eslintignore
├── .eslintrc
├── .gitignore
├── .travis.yml
├── app
├── InitData
│ ├── activity.js
│ ├── category.js
│ ├── cities.js
│ ├── delivery.js
│ ├── entry.js
│ ├── explain.js
│ ├── hongbao.js
│ ├── payments.js
│ ├── rate.js
│ └── remark.js
├── controller
│ ├── admin
│ │ └── admin.js
│ ├── member
│ │ └── vipCart.js
│ ├── promotion
│ │ └── hongbao.js
│ ├── shopping
│ │ ├── category.js
│ │ ├── food.js
│ │ └── shop.js
│ ├── statis
│ │ └── statis.js
│ ├── ugc
│ │ └── rating.js
│ ├── upload.js
│ ├── v1
│ │ ├── addre.js
│ │ ├── captchas.js
│ │ ├── carts.js
│ │ ├── city.js
│ │ ├── order.js
│ │ ├── remark.js
│ │ └── search.js
│ ├── v2
│ │ ├── entry.js
│ │ └── user.js
│ └── v3
│ │ └── explain.js
├── extend
│ └── helper.js
├── middleware
│ ├── checkAdmin.js
│ ├── checkSuperAdmin.js
│ └── check_api_token.js
├── model
│ ├── activity.js
│ ├── address.js
│ ├── admin.js
│ ├── cart.js
│ ├── category.js
│ ├── city.js
│ ├── delivery.js
│ ├── entry.js
│ ├── explain.js
│ ├── food.js
│ ├── hongbao.js
│ ├── ids.js
│ ├── menu.js
│ ├── order.js
│ ├── payments.js
│ ├── rating.js
│ ├── remark.js
│ ├── shop.js
│ ├── user.js
│ └── userInfo.js
├── public
│ └── temp
│ │ ├── 1669ffd40d130.png
│ │ ├── 1669ffd4f6032.png
│ │ ├── 1669ffd5b9931.png
│ │ ├── 166a00081cc33.png
│ │ ├── 166a000a3ac34.png
│ │ ├── 166a445d19535.png
│ │ ├── 166a445d88e36.png
│ │ ├── 166a44605bf37.png
│ │ ├── 166a4cb194a39.png
│ │ ├── 166a4cb227438.png
│ │ ├── 166a4cb3bb440.png
│ │ ├── 166a5042e7741.png
│ │ ├── 166a504b61d42.png
│ │ ├── 166a50b095d43.png
│ │ ├── 166a50c79ec44.png
│ │ ├── 166a50cc1fd45.png
│ │ ├── 166be97f19f46.png
│ │ ├── 166be9819c848.png
│ │ ├── 166be98217b47.png
│ │ ├── 166c297677250.png
│ │ ├── 166c29773c749.png
│ │ ├── 166c297869051.png
│ │ ├── 166c29800f252.png
│ │ ├── 166c3322a8553.png
│ │ ├── 166c3a453fa54.png
│ │ ├── 166c414dffa55.png
│ │ ├── 166c807a60856.png
│ │ ├── 166c810c34d57.png
│ │ ├── 166cd80824658.png
│ │ ├── 166e7b704e959.png
│ │ ├── 166e7c285a760.png
│ │ ├── 166e7c303c461.png
│ │ ├── 166e7c3bbb262.png
│ │ ├── 166e7c3eed963.png
│ │ ├── 166e827ad7164.png
│ │ ├── 166e82820b265.png
│ │ ├── 166f24683de66.png
│ │ ├── 166f246de0767.png
│ │ ├── 16705c7696668.png
│ │ ├── 16705c7a8a769.png
│ │ ├── 1670fdf83cd70.png
│ │ ├── 1670fdfa39371.png
│ │ └── 1670fdfd42072.jpg
├── router.js
└── service
│ ├── address.js
│ ├── admin
│ └── admin.js
│ ├── member
│ └── vipCart.js
│ ├── promotion
│ └── hongbao.js
│ ├── shopping
│ ├── category.js
│ ├── food.js
│ └── shop.js
│ ├── statis
│ └── statis.js
│ ├── ugc
│ └── rating.js
│ ├── upload.js
│ ├── v1
│ ├── addre.js
│ ├── captchas.js
│ ├── carts.js
│ ├── city.js
│ ├── order.js
│ ├── remark.js
│ └── search.js
│ ├── v2
│ ├── entry.js
│ └── user.js
│ └── v3
│ └── explain.js
├── appveyor.yml
├── config
├── config.default.js
└── plugin.js
├── deploy.sh
├── package.json
├── readme.md
├── server.md
└── test
└── app
└── controller
└── home.test.js
/.autod.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | write: true,
5 | prefix: '^',
6 | plugin: 'autod-egg',
7 | test: [
8 | 'test',
9 | 'benchmark',
10 | ],
11 | dep: [
12 | 'egg',
13 | 'egg-scripts',
14 | ],
15 | devdep: [
16 | 'egg-ci',
17 | 'egg-bin',
18 | 'egg-mock',
19 | 'autod',
20 | 'autod-egg',
21 | 'eslint',
22 | 'eslint-config-egg',
23 | 'webstorm-disable-index',
24 | ],
25 | exclude: [
26 | './test/fixtures',
27 | './dist',
28 | ],
29 | };
30 |
31 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | coverage
2 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "eslint-config-egg"
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | logs/
2 | npm-debug.log
3 | yarn-error.log
4 | node_modules/
5 | package-lock.json
6 | yarn.lock
7 | coverage/
8 | .idea/
9 | run/
10 | .DS_Store
11 | *.sw*
12 | *.un~
13 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: node_js
3 | node_js:
4 | - '8'
5 | install:
6 | - npm i npminstall && npminstall
7 | script:
8 | - npm run ci
9 | after_script:
10 | - npminstall codecov && codecov
11 |
--------------------------------------------------------------------------------
/app/InitData/activity.js:
--------------------------------------------------------------------------------
1 | module.exports = [{
2 | description: "",
3 | icon_color: "3FBDE6",
4 | icon_name: "品",
5 | id: 8,
6 | name: "品牌商家",
7 | ranking_weight: 7
8 | },
9 | {
10 | description: "已加入“外卖保”计划,食品安全有保障",
11 | icon_color: "999999",
12 | icon_name: "保",
13 | id: 7,
14 | name: "外卖保",
15 | ranking_weight: 6
16 | },
17 | {
18 | description: "新店",
19 | icon_color: "E8842D",
20 | icon_name: "新",
21 | id: 5,
22 | name: "新店",
23 | ranking_weight: 4
24 | },
25 | {
26 | description: "该商家支持开发票,请在下单时填写好发票抬头",
27 | icon_color: "999999",
28 | icon_name: "票",
29 | id: 4,
30 | name: "开发票",
31 | ranking_weight: 3
32 | },
33 | {
34 | description: "可使用支付宝、微信、手机QQ进行在线支付",
35 | icon_color: "FF4E00",
36 | icon_name: "付",
37 | id: 3,
38 | name: "在线支付",
39 | ranking_weight: 2
40 | },
41 | {
42 | description: "准时必达,超时秒赔",
43 | icon_color: "57A9FF",
44 | icon_name: "准",
45 | id: 9,
46 | name: "准时达",
47 | ranking_weight: 1
48 | }
49 | ]
--------------------------------------------------------------------------------
/app/InitData/category.js:
--------------------------------------------------------------------------------
1 | module.exports = [{
2 | count: 0,
3 | ids: [
4 | 207,
5 | 220,
6 | 260,
7 | 233,
8 | 239,
9 | 244,
10 | 248,
11 | 252
12 | ],
13 | image_url: "",
14 | level: 1,
15 | name: "全部商家"
16 | },
17 | {
18 | count: 0,
19 | id: 207,
20 | ids: [
21 | 207
22 | ],
23 | image_url: "bff533cf9617bd57fe1dfb05603bebcfpng",
24 | level: 1,
25 | name: "快餐便当",
26 | sub_categories: [{
27 | count: 0,
28 | id: 207,
29 | image_url: "44545a0518aab93817cfe611e88bb702png",
30 | level: 1,
31 | name: "全部快餐便当"
32 | },
33 | {
34 | count: 0,
35 | id: 265,
36 | image_url: "be84bc4d7cf12deee9115b16eb099302png",
37 | level: 2,
38 | name: "简餐"
39 | },
40 | {
41 | count: 0,
42 | id: 209,
43 | image_url: "66b78c0e7099c278977298d7c6042c80png",
44 | level: 2,
45 | name: "盖浇饭"
46 | },
47 | {
48 | count: 0,
49 | id: 213,
50 | image_url: "02e6c9e3bf338ec0ba0d923717b9f8acpng",
51 | level: 2,
52 | name: "米粉面馆"
53 | },
54 | {
55 | count: 0,
56 | id: 215,
57 | image_url: "af6ab89041b3e77fe115d1e4b72d69f0png",
58 | level: 2,
59 | name: "包子粥店"
60 | },
61 | {
62 | count: 0,
63 | id: 219,
64 | image_url: "eddd9dc7e5d21debe2fb278ae01fefe9png",
65 | level: 2,
66 | name: "香锅砂锅"
67 | },
68 | {
69 | count: 0,
70 | id: 214,
71 | image_url: "4d347d0dc65dd75fb2911256aabf2327png",
72 | level: 2,
73 | name: "麻辣烫"
74 | },
75 | {
76 | count: 0,
77 | id: 217,
78 | image_url: "65b575c2278a3f6e5c70af45b578cbeepng",
79 | level: 2,
80 | name: "饺子馄饨"
81 | },
82 | {
83 | count: 0,
84 | id: 212,
85 | image_url: "7d47af01fccc46fc3621865a9cc07c93png",
86 | level: 2,
87 | name: "汉堡"
88 | },
89 | {
90 | count: 0,
91 | id: 216,
92 | image_url: "4c6af48f68284ad91c6d95d2bd3f4aa6png",
93 | level: 2,
94 | name: "生煎锅贴"
95 | },
96 | {
97 | count: 0,
98 | id: 267,
99 | image_url: "79637dc36d67de4fe48d121ea77b3eddpng",
100 | level: 2,
101 | name: "黄焖鸡米饭"
102 | },
103 | {
104 | count: 0,
105 | id: 266,
106 | image_url: "c09d1ff71384e2e1664f72e0a928810dpng",
107 | level: 2,
108 | name: "烧腊饭"
109 | },
110 | {
111 | count: 0,
112 | id: 269,
113 | image_url: "180cb951c2d4eb2e220debf4571bf83apng",
114 | level: 2,
115 | name: "煲仔饭"
116 | },
117 | {
118 | count: 0,
119 | id: 268,
120 | image_url: "cdf208b399b854e456f23d28b1972e97png",
121 | level: 2,
122 | name: "咖喱饭"
123 | }
124 | ]
125 | },
126 | {
127 | count: 0,
128 | id: 220,
129 | ids: [
130 | 220
131 | ],
132 | image_url: "655ac1bfd1e818013a9f099e964f1e9djpeg",
133 | level: 1,
134 | name: "特色菜系",
135 | sub_categories: [{
136 | count: 0,
137 | id: 220,
138 | image_url: "ef32dabbcd88fbed5a336383e74c733dpng",
139 | level: 1,
140 | name: "全部特色菜系"
141 | },
142 | {
143 | count: 0,
144 | id: 221,
145 | image_url: "43b0e4694f8ebc393cce6723d5df5222png",
146 | level: 2,
147 | name: "川湘菜"
148 | },
149 | {
150 | count: 0,
151 | id: 263,
152 | image_url: "94ac841e2c3e27f8eeeaa917574ed574png",
153 | level: 2,
154 | name: "其他菜系"
155 | },
156 | {
157 | count: 0,
158 | id: 225,
159 | image_url: "2d098842683548f9626cf0a8c879257dpng",
160 | level: 2,
161 | name: "江浙菜"
162 | },
163 | {
164 | count: 0,
165 | id: 222,
166 | image_url: "e320bf1ab9762cb1faad27d79f51219cpng",
167 | level: 2,
168 | name: "粤菜"
169 | },
170 | {
171 | count: 0,
172 | id: 232,
173 | image_url: "a33f1ec0044ddd4d282fbc8b1f0a946fpng",
174 | level: 2,
175 | name: "海鲜"
176 | },
177 | {
178 | count: 0,
179 | id: 231,
180 | image_url: "c03d81f550eb849ed2d4d0290ced9099png",
181 | level: 2,
182 | name: "火锅烤鱼"
183 | },
184 | {
185 | count: 0,
186 | id: 223,
187 | image_url: "aa4de1e9b54170cf495d8052407658c5png",
188 | level: 2,
189 | name: "东北菜"
190 | },
191 | {
192 | count: 0,
193 | id: 226,
194 | image_url: "741d15270496d7699dd2e7804fccc7a1png",
195 | level: 2,
196 | name: "西北菜"
197 | },
198 | {
199 | count: 0,
200 | id: 224,
201 | image_url: "54dabf93116f4a336fcc91431be43828png",
202 | level: 2,
203 | name: "云南菜"
204 | },
205 | {
206 | count: 0,
207 | id: 228,
208 | image_url: "a7e6d9cf1993fa4fe0bd02d74d40c9c2png",
209 | level: 2,
210 | name: "新疆菜"
211 | },
212 | {
213 | count: 0,
214 | id: 227,
215 | image_url: "e19bf59188a157dfc372b3d254fc986dpng",
216 | level: 2,
217 | name: "鲁菜"
218 | }
219 | ]
220 | },
221 | {
222 | count: 0,
223 | id: 260,
224 | ids: [
225 | 260
226 | ],
227 | image_url: "1babf6efbfdb0ef701f19689a5529e5fjpeg",
228 | level: 1,
229 | name: "异国料理",
230 | sub_categories: [{
231 | count: 0,
232 | id: 260,
233 | image_url: "754c5c2ad1b01668a7186ec5f0fb0e59png",
234 | level: 1,
235 | name: "全部异国料理"
236 | },
237 | {
238 | count: 0,
239 | id: 229,
240 | image_url: "cf8c84a2fe5ecf27b21bcbddc1724d36png",
241 | level: 2,
242 | name: "日韩料理"
243 | },
244 | {
245 | count: 0,
246 | id: 230,
247 | image_url: "78c45200d58e5c02cb70fb8287df732dpng",
248 | level: 2,
249 | name: "西餐"
250 | },
251 | {
252 | count: 0,
253 | id: 211,
254 | image_url: "bb7eb2afe778ba9afbe54f9d282818d1png",
255 | level: 2,
256 | name: "披萨意面"
257 | },
258 | {
259 | count: 0,
260 | id: 264,
261 | image_url: "614053401fddc171eed0436f3cd1f7dcpng",
262 | level: 2,
263 | name: "东南亚菜"
264 | }
265 | ]
266 | },
267 | {
268 | count: 0,
269 | id: 233,
270 | ids: [
271 | 233
272 | ],
273 | image_url: "435a7eda7659bac613e524ca7c1ae12epng",
274 | level: 1,
275 | name: "小吃夜宵",
276 | sub_categories: [{
277 | count: 0,
278 | id: 233,
279 | image_url: "7d714540b1590552d991fd731e8772a3png",
280 | level: 1,
281 | name: "全部小吃夜宵"
282 | },
283 | {
284 | count: 0,
285 | id: 236,
286 | image_url: "d049fb617edcea921185258d1675db83png",
287 | level: 2,
288 | name: "小龙虾"
289 | },
290 | {
291 | count: 0,
292 | id: 237,
293 | image_url: "90483b16d9598aec798263220eb3a821png",
294 | level: 2,
295 | name: "地方小吃"
296 | },
297 | {
298 | count: 0,
299 | id: 218,
300 | image_url: "3c6e2763cf4ee56f18fd1b7360585fb3png",
301 | level: 2,
302 | name: "烧烤"
303 | },
304 | {
305 | count: 0,
306 | id: 234,
307 | image_url: "71164ef684e8a13b5e66a20a1c55671cpng",
308 | level: 2,
309 | name: "炸鸡炸串"
310 | },
311 | {
312 | count: 0,
313 | id: 235,
314 | image_url: "efdba78945f83ed1e8e6e838718b4c65png",
315 | level: 2,
316 | name: "鸭脖卤味"
317 | },
318 | {
319 | count: 0,
320 | id: 238,
321 | image_url: "d7e0be7e5420e213ea42e4fa3efa762bpng",
322 | level: 2,
323 | name: "零食"
324 | }
325 | ]
326 | },
327 | {
328 | count: 0,
329 | id: 239,
330 | ids: [
331 | 239
332 | ],
333 | image_url: "48243703799592368585b23589cf3ba8png",
334 | level: 1,
335 | name: "甜品饮品",
336 | sub_categories: [{
337 | count: 0,
338 | id: 239,
339 | image_url: "3233a4cac2e5e02cade80cce22992796png",
340 | level: 1,
341 | name: "全部甜品饮品"
342 | },
343 | {
344 | count: 0,
345 | id: 240,
346 | image_url: "3a40add809b4405e677c4cab574e56c4png",
347 | level: 2,
348 | name: "奶茶果汁"
349 | },
350 | {
351 | count: 0,
352 | id: 241,
353 | image_url: "213cbac0242d4845d1d28af0fa5fe35epng",
354 | level: 2,
355 | name: "甜品"
356 | },
357 | {
358 | count: 0,
359 | id: 242,
360 | image_url: "c2f05ef82a7ee44b7848b7fb598d42e3png",
361 | level: 2,
362 | name: "咖啡"
363 | }
364 | ]
365 | },
366 | {
367 | count: 0,
368 | id: 244,
369 | ids: [
370 | 244
371 | ],
372 | image_url: "6235a6fce94bed63a21508f68a72c158png",
373 | level: 1,
374 | name: "果蔬生鲜",
375 | sub_categories: [{
376 | count: 0,
377 | id: 244,
378 | image_url: "1ce198f37a81285f4afa2aaf826a558fpng",
379 | level: 1,
380 | name: "全部果蔬生鲜"
381 | },
382 | {
383 | count: 0,
384 | id: 245,
385 | image_url: "a831a37ec670ca93cd35a8a6b5a20e62png",
386 | level: 2,
387 | name: "水果"
388 | },
389 | {
390 | count: 0,
391 | id: 247,
392 | image_url: "6d3cef77e055d03598cba821ebcf1f06png",
393 | level: 2,
394 | name: "生鲜"
395 | },
396 | {
397 | count: 0,
398 | id: 246,
399 | image_url: "1729548b88614c1b3a6e71ef7f89f294png",
400 | level: 2,
401 | name: "蔬菜"
402 | },
403 | {
404 | count: 0,
405 | id: 270,
406 | image_url: "a2ab438ee4ac09e6e53b3f96694bac81png",
407 | level: 2,
408 | name: "海鲜水产"
409 | }
410 | ]
411 | },
412 | {
413 | count: 0,
414 | id: 248,
415 | ids: [
416 | 248
417 | ],
418 | image_url: "0e07558e305abfb2618ae760142222f9png",
419 | level: 1,
420 | name: "鲜花蛋糕",
421 | sub_categories: [{
422 | count: 0,
423 | id: 248,
424 | image_url: "3edf3f4ef8ed1d300896c5b9178685ebpng",
425 | level: 1,
426 | name: "全部鲜花蛋糕"
427 | },
428 | {
429 | count: 0,
430 | id: 251,
431 | image_url: "cf598de7338b4bf9dd2924736c4ec9d2png",
432 | level: 2,
433 | name: "鲜花"
434 | },
435 | {
436 | count: 0,
437 | id: 249,
438 | image_url: "ac94b005c97ef158282326cb49389893png",
439 | level: 2,
440 | name: "蛋糕"
441 | },
442 | {
443 | count: 0,
444 | id: 250,
445 | image_url: "512232422a83e25a2c0a5588b7b6e730png",
446 | level: 2,
447 | name: "面包"
448 | }
449 | ]
450 | },
451 | {
452 | count: 0,
453 | id: 252,
454 | ids: [
455 | 252
456 | ],
457 | image_url: "ac15c5dd59b641bdfdeb822362547fb4png",
458 | level: 1,
459 | name: "商店超市",
460 | sub_categories: [{
461 | count: 0,
462 | id: 252,
463 | image_url: "df21b511f287ccb402e68285d2653caepng",
464 | level: 1,
465 | name: "全部商店超市"
466 | },
467 | {
468 | count: 0,
469 | id: 254,
470 | image_url: "92ae70438be9a3adfc5a560c1e6ae818png",
471 | level: 2,
472 | name: "超市"
473 | },
474 | {
475 | count: 0,
476 | id: 271,
477 | image_url: "841d136b17fa4cb871a296c9e4997cfapng",
478 | level: 2,
479 | name: "便利店"
480 | },
481 | {
482 | count: 0,
483 | id: 274,
484 | image_url: "7df84232aebbb5ffb53e564c9e328d31png",
485 | level: 2,
486 | name: "名酒坊"
487 | },
488 | {
489 | count: 0,
490 | id: 273,
491 | image_url: "c2b0e2b27ea55a9a7211f14ad95dcd0apng",
492 | level: 2,
493 | name: "零食饮料"
494 | },
495 | {
496 | count: 0,
497 | id: 255,
498 | image_url: "825031dc99e1f99c26feb7186b6cf3a6png",
499 | level: 2,
500 | name: "水站"
501 | },
502 | {
503 | count: 0,
504 | id: 258,
505 | image_url: "54b7ce87994d6770f1ead57b0038c569png",
506 | level: 2,
507 | name: "茶"
508 | },
509 | {
510 | count: 0,
511 | id: 256,
512 | image_url: "f6460e330d25dabd4fd8db07cf53f039png",
513 | level: 2,
514 | name: "奶站"
515 | },
516 | {
517 | count: 0,
518 | id: 257,
519 | image_url: "b435af6662fd0b3e9fb6537474753f72png",
520 | level: 2,
521 | name: "粮油"
522 | },
523 | {
524 | count: 0,
525 | id: 272,
526 | image_url: "f7e32a289deca477c286362e3a1bc2bcpng",
527 | level: 2,
528 | name: "美妆母婴"
529 | }
530 | ]
531 | }
532 | ]
--------------------------------------------------------------------------------
/app/InitData/delivery.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | color: "57A9FF",
3 | id: 1,
4 | is_solid: true,
5 | text: "蜂鸟专送"
6 | }
--------------------------------------------------------------------------------
/app/InitData/entry.js:
--------------------------------------------------------------------------------
1 | module.exports = [{
2 | id: 15,
3 | is_in_serving: true,
4 | description: "附近美食一网打尽",
5 | title: "美食",
6 | link: "eleme://restaurants?filter_key=%7B%22category_schema%22%3A%7B%22category_name%22%3A%22%5Cu7f8e%5Cu98df%22%2C%22complex_category_ids%22%3A%5B207%2C220%2C233%2C260%5D%2C%22is_show_all_category%22%3Afalse%7D%2C%22restaurant_category_id%22%3A%7B%22id%22%3A207%2C%22name%22%3A%22%5Cu5feb%5Cu9910%5Cu4fbf%5Cu5f53%22%2C%22sub_categories%22%3A%5B%5D%2C%22image_url%22%3A%22%22%7D%2C%22activities%22%3A%5B%5D%7D&target_name=%E7%BE%8E%E9%A3%9F&animation_type=1&is_need_mark=0&banner_type=",
7 | image_url: "/b/7e/d1890cf73ae6f2adb97caa39de7fcjpeg.jpeg",
8 | icon_url: "",
9 | title_color: ""
10 | },
11 | {
12 | id: 20,
13 | is_in_serving: true,
14 | description: "苦了累了,来点甜的",
15 | title: "甜品饮品",
16 | link: "eleme://restaurants?filter_key=%7B%22category_schema%22%3A%7B%22category_name%22%3A%22%5Cu751c%5Cu54c1%5Cu996e%5Cu54c1%22%2C%22complex_category_ids%22%3A%5B240%2C241%2C242%5D%2C%22is_show_all_category%22%3Atrue%7D%2C%22restaurant_category_id%22%3A%7B%22id%22%3A239%2C%22name%22%3A%22%5Cu751c%5Cu54c1%5Cu996e%5Cu54c1%22%2C%22sub_categories%22%3A%5B%5D%2C%22image_url%22%3A%22%22%7D%2C%22activities%22%3A%5B%5D%7D&target_name=%E7%94%9C%E5%93%81%E9%A5%AE%E5%93%81&animation_type=1&is_need_mark=0&banner_type=",
17 | image_url: "/2/35/696aa5cf9820adada9b11a3d14bf5jpeg.jpeg",
18 | icon_url: "",
19 | title_color: ""
20 | },
21 | {
22 | id: 10,
23 | is_in_serving: true,
24 | description: "足不出户,便利回家",
25 | title: "商超便利",
26 | link: "eleme://restaurants?filter_key=%7B%22category_schema%22%3A%7B%22category_name%22%3A%22%5Cu5546%5Cu8d85%5Cu4fbf%5Cu5229%22%2C%22complex_category_ids%22%3A%5B254%2C255%2C256%2C257%2C258%2C271%2C272%2C273%2C274%5D%2C%22is_show_all_category%22%3Atrue%7D%2C%22restaurant_category_id%22%3A%7B%22id%22%3A252%2C%22name%22%3A%22%5Cu5546%5Cu5e97%5Cu8d85%5Cu5e02%22%2C%22sub_categories%22%3A%5B%5D%2C%22image_url%22%3A%22%22%7D%2C%22activities%22%3A%5B%5D%7D&target_name=%E5%95%86%E8%B6%85%E4%BE%BF%E5%88%A9&animation_type=1&is_need_mark=0&banner_type=",
27 | image_url: "/0/da/f42235e6929a5cb0e7013115ce78djpeg.jpeg",
28 | icon_url: "",
29 | title_color: ""
30 | },
31 | {
32 | id: 1,
33 | is_in_serving: true,
34 | description: "0元早餐0起送,每天都有新花样。",
35 | title: "预订早餐",
36 | link: "eleme://web?url=https%3A%2F%2Fzaocan.ele.me&target_name=%E9%A2%84%E8%AE%A2%E6%97%A9%E9%A4%90&animation_type=1&is_need_mark=&banner_type=",
37 | image_url: "/d/49/7757ff22e8ab28e7dfa5f7e2c2692jpeg.jpeg",
38 | icon_url: "",
39 | title_color: ""
40 | },
41 | {
42 | id: 8,
43 | is_in_serving: true,
44 | description: "一天变女神",
45 | title: "果蔬生鲜",
46 | link: "eleme://restaurants?filter_key=%7B%22category_schema%22%3A%7B%22category_name%22%3A%22%5Cu679c%5Cu852c%5Cu751f%5Cu9c9c%22%2C%22complex_category_ids%22%3A%5B245%2C246%2C247%5D%2C%22is_show_all_category%22%3Atrue%7D%2C%22restaurant_category_id%22%3A%7B%22id%22%3A244%2C%22name%22%3A%22%5Cu679c%5Cu852c%5Cu751f%5Cu9c9c%22%2C%22sub_categories%22%3A%5B%5D%2C%22image_url%22%3A%22%22%7D%2C%22activities%22%3A%5B%5D%7D&target_name=%E6%9E%9C%E8%94%AC%E7%94%9F%E9%B2%9C&animation_type=1&is_need_mark=0&banner_type=",
47 | image_url: "/4/34/ea0d51c9608310cf41faa5de6b8efjpeg.jpeg",
48 | icon_url: "",
49 | title_color: ""
50 | },
51 | {
52 | id: 403297,
53 | is_in_serving: true,
54 | description: "大胆尝鲜,遇见惊喜",
55 | title: "新店特惠",
56 | link: "eleme://restaurants?filter_key=%7B%22category_schema%22%3A%7B%22category_name%22%3A%22%5Cu65b0%5Cu5e97%5Cu7279%5Cu60e0%22%2C%22complex_category_ids%22%3A%5B207%2C220%2C233%2C239%2C244%2C248%2C252%2C260%5D%2C%22is_show_all_category%22%3Atrue%7D%2C%22restaurant_category_id%22%3A%7B%22id%22%3A207%2C%22name%22%3A%22%5Cu5feb%5Cu9910%5Cu4fbf%5Cu5f53%22%2C%22sub_categories%22%3A%5B%5D%2C%22image_url%22%3A%22%22%7D%2C%22support_ids%22%3A%5B-1%5D%2C%22activities%22%3A%5B%5D%7D&target_name=%E6%96%B0%E5%BA%97%E7%89%B9%E6%83%A0&animation_type=1&is_need_mark=0&banner_type=",
57 | image_url: "/a/fa/d41b04d520d445dc5de42dae9a384jpeg.jpeg",
58 | icon_url: "",
59 | title_color: ""
60 | },
61 | {
62 | id: 92,
63 | is_in_serving: true,
64 | description: "准时必达,超时赔付",
65 | title: "准时达",
66 | link: "eleme://restaurants?filter_key=%7B%22support_ids%22%3A%5B9%5D%2C%22activities%22%3A%5B%7B%22id%22%3A9%2C%22name%22%3A%22%5Cu51c6%5Cu65f6%5Cu8fbe%22%2C%22icon_name%22%3A%22%5Cu51c6%22%2C%22icon_color%22%3A%22E8842D%22%2C%22is_need_filling%22%3A0%2C%22is_multi_choice%22%3A1%2C%22filter_value%22%3A9%2C%22filter_key%22%3A%22support_ids%22%2C%22description%22%3A%22%5Cu51c6%5Cu65f6%5Cu8fbe%22%7D%5D%7D&target_name=%E5%87%86%E6%97%B6%E8%BE%BE&animation_type=1&is_need_mark=0&banner_type=",
67 | image_url: "/3/84/8e031bf7b3c036b4ec19edff16e46jpeg.jpeg",
68 | icon_url: "",
69 | title_color: ""
70 | },
71 | {
72 | id: 225,
73 | is_in_serving: true,
74 | description: "有菜有肉,营养均衡",
75 | title: "简餐",
76 | link: "eleme://restaurants?filter_key=%7B%22activity_types%22%3A%5B3%5D%2C%22category_schema%22%3A%7B%22category_name%22%3A%22%5Cu7b80%5Cu9910%22%2C%22complex_category_ids%22%3A%5B209%2C212%2C215%2C265%5D%2C%22is_show_all_category%22%3Atrue%7D%2C%22restaurant_category_id%22%3A%7B%22id%22%3A207%2C%22name%22%3A%22%5Cu5feb%5Cu9910%5Cu4fbf%5Cu5f53%22%2C%22sub_categories%22%3A%5B%5D%2C%22image_url%22%3A%22%22%7D%2C%22activities%22%3A%5B%7B%22id%22%3A3%2C%22name%22%3A%22%5Cu4e0b%5Cu5355%5Cu7acb%5Cu51cf%22%2C%22icon_name%22%3A%22%5Cu51cf%22%2C%22icon_color%22%3A%22f07373%22%2C%22is_need_filling%22%3A1%2C%22is_multi_choice%22%3A0%2C%22filter_value%22%3A3%2C%22filter_key%22%3A%22activity_types%22%7D%5D%7D&target_name=%E7%AE%80%E9%A4%90&animation_type=1&is_need_mark=0&banner_type=",
77 | image_url: "/d/38/7bddb07503aea4b711236348e2632jpeg.jpeg",
78 | icon_url: "",
79 | title_color: ""
80 | },
81 | {
82 | id: 65,
83 | is_in_serving: true,
84 | description: "",
85 | title: "土豪推荐",
86 | link: "eleme://restaurants?filter_key=%7B%22activities%22%3A%5B%7B%22filter_key%22%3A%22tags%22%2C%22filter_value%22%3A0%7D%5D%7D&target_name=%E5%9C%9F%E8%B1%AA%E6%8E%A8%E8%8D%90&animation_type=1&is_need_mark=0&banner_type=",
87 | image_url: "/e/7e/02b72b5e63c127d5bfae57b8e4ab1jpeg.jpeg",
88 | icon_url: "",
89 | title_color: ""
90 | },
91 | {
92 | id: 236,
93 | is_in_serving: true,
94 | description: "大口大口把你吃掉",
95 | title: "汉堡薯条",
96 | link: "eleme://restaurants?filter_key=%7B%22category_schema%22%3A%7B%22category_name%22%3A%22%5Cu6c49%5Cu5821%22%2C%22complex_category_ids%22%3A%5B212%5D%2C%22is_show_all_category%22%3Atrue%7D%2C%22restaurant_category_id%22%3A%7B%22id%22%3A207%2C%22name%22%3A%22%5Cu5feb%5Cu9910%5Cu4fbf%5Cu5f53%22%2C%22sub_categories%22%3A%5B%5D%2C%22image_url%22%3A%22%22%7D%2C%22activities%22%3A%5B%5D%7D&target_name=%E6%B1%89%E5%A0%A1%E8%96%AF%E6%9D%A1&animation_type=1&is_need_mark=0&banner_type=",
97 | image_url: "/b/7f/432619fb21a40b05cd25d11eca02djpeg.jpeg",
98 | icon_url: "",
99 | title_color: ""
100 | },
101 | {
102 | id: 289,
103 | is_in_serving: true,
104 | description: "老字号,好味道",
105 | title: "包子粥店",
106 | link: "eleme://restaurants?filter_key=%7B%22category_schema%22%3A%7B%22category_name%22%3A%22%5Cu5305%5Cu5b50%5Cu7ca5%5Cu5e97%22%2C%22complex_category_ids%22%3A%5B215%5D%2C%22is_show_all_category%22%3Atrue%7D%2C%22restaurant_category_id%22%3A%7B%22id%22%3A207%2C%22name%22%3A%22%5Cu5feb%5Cu9910%5Cu4fbf%5Cu5f53%22%2C%22sub_categories%22%3A%5B%5D%2C%22image_url%22%3A%22%22%7D%2C%22activities%22%3A%5B%5D%7D&target_name=%E5%8C%85%E5%AD%90%E7%B2%A5%E5%BA%97&animation_type=1&is_need_mark=0&banner_type=",
107 | image_url: "/2/17/244241b514affc0f12f4168cf6628jpeg.jpeg",
108 | icon_url: "",
109 | title_color: ""
110 | },
111 | {
112 | id: 9,
113 | is_in_serving: true,
114 | description: "内心小公举,一直被宠爱",
115 | title: "鲜花蛋糕",
116 | link: "eleme://restaurants?filter_key=%7B%22category_schema%22%3A%7B%22category_name%22%3A%22%5Cu9c9c%5Cu82b1%5Cu86cb%5Cu7cd5%22%2C%22complex_category_ids%22%3A%5B249%2C250%2C251%5D%2C%22is_show_all_category%22%3Atrue%7D%2C%22restaurant_category_id%22%3A%7B%22id%22%3A248%2C%22name%22%3A%22%5Cu9c9c%5Cu82b1%5Cu86cb%5Cu7cd5%22%2C%22sub_categories%22%3A%5B%5D%2C%22image_url%22%3A%22%22%7D%2C%22activities%22%3A%5B%5D%7D&target_name=%E9%B2%9C%E8%8A%B1%E8%9B%8B%E7%B3%95&animation_type=1&is_need_mark=0&banner_type=",
117 | image_url: "/8/83/171fd98b85dee3b3f4243b7459b48jpeg.jpeg",
118 | icon_url: "",
119 | title_color: ""
120 | },
121 | {
122 | id: 286,
123 | is_in_serving: true,
124 | description: "",
125 | title: "麻辣烫",
126 | link: "eleme://restaurants?filter_key=%7B%22category_schema%22%3A%7B%22category_name%22%3A%22%5Cu9ebb%5Cu8fa3%5Cu70eb%22%2C%22complex_category_ids%22%3A%5B214%5D%2C%22is_show_all_category%22%3Atrue%7D%2C%22restaurant_category_id%22%3A%7B%22id%22%3A207%2C%22name%22%3A%22%5Cu5feb%5Cu9910%5Cu4fbf%5Cu5f53%22%2C%22sub_categories%22%3A%5B%5D%2C%22image_url%22%3A%22%22%7D%2C%22activities%22%3A%5B%5D%7D&target_name=%E9%BA%BB%E8%BE%A3%E7%83%AB&animation_type=1&is_need_mark=0&banner_type=",
127 | image_url: "/3/c7/a9ef469a12e7a596b559145b87f09jpeg.jpeg",
128 | icon_url: "",
129 | title_color: ""
130 | },
131 | {
132 | id: 288,
133 | is_in_serving: true,
134 | description: "无辣不欢",
135 | title: "川湘菜",
136 | link: "eleme://restaurants?filter_key=%7B%22category_schema%22%3A%7B%22category_name%22%3A%22%5Cu5ddd%5Cu6e58%5Cu83dc%22%2C%22complex_category_ids%22%3A%5B221%5D%2C%22is_show_all_category%22%3Atrue%7D%2C%22restaurant_category_id%22%3A%7B%22id%22%3A220%2C%22name%22%3A%22%5Cu7279%5Cu8272%5Cu83dc%5Cu7cfb%22%2C%22sub_categories%22%3A%5B%5D%2C%22image_url%22%3A%22%22%7D%2C%22activities%22%3A%5B%5D%7D&target_name=%E5%B7%9D%E6%B9%98%E8%8F%9C&animation_type=1&is_need_mark=0&banner_type=",
137 | image_url: "/9/7c/9700836a33e05c2410bda8da59117jpeg.jpeg",
138 | icon_url: "",
139 | title_color: ""
140 | },
141 | {
142 | id: 287,
143 | is_in_serving: true,
144 | description: "西餐始祖,欧洲的味道",
145 | title: "披萨意面",
146 | link: "eleme://restaurants?filter_key=%7B%22category_schema%22%3A%7B%22category_name%22%3A%22%5Cu62ab%5Cu8428%5Cu610f%5Cu9762%22%2C%22complex_category_ids%22%3A%5B211%5D%2C%22is_show_all_category%22%3Atrue%7D%2C%22restaurant_category_id%22%3A%7B%22id%22%3A260%2C%22name%22%3A%22%5Cu5f02%5Cu56fd%5Cu6599%5Cu7406%22%2C%22sub_categories%22%3A%5B%5D%2C%22image_url%22%3A%22%22%7D%2C%22activities%22%3A%5B%5D%7D&target_name=%E6%8A%AB%E8%90%A8%E6%84%8F%E9%9D%A2&animation_type=1&is_need_mark=0&banner_type=",
147 | image_url: "/7/b6/235761e50d391445f021922b71789jpeg.jpeg",
148 | icon_url: "",
149 | title_color: ""
150 | },
151 | {
152 | id: 285,
153 | is_in_serving: true,
154 | description: "寿司定食,泡菜烤肉",
155 | title: "日韩料理",
156 | link: "eleme://restaurants?filter_key=%7B%22category_schema%22%3A%7B%22category_name%22%3A%22%5Cu65e5%5Cu97e9%5Cu6599%5Cu7406%22%2C%22complex_category_ids%22%3A%5B229%5D%2C%22is_show_all_category%22%3Atrue%7D%2C%22restaurant_category_id%22%3A%7B%22id%22%3A260%2C%22name%22%3A%22%5Cu5f02%5Cu56fd%5Cu6599%5Cu7406%22%2C%22sub_categories%22%3A%5B%5D%2C%22image_url%22%3A%22%22%7D%2C%22activities%22%3A%5B%5D%7D&target_name=%E6%97%A5%E9%9F%A9%E6%96%99%E7%90%86&animation_type=1&is_need_mark=0&banner_type=",
157 | image_url: "/6/1a/1e0f448be0624c62db416e864d2afjpeg.jpeg",
158 | icon_url: "",
159 | title_color: ""
160 | }
161 | ]
--------------------------------------------------------------------------------
/app/InitData/explain.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | activityCaption: "活动问题",
3 | activityContent: '### Q1: 我是新用户,为什么不能享受新用户下单立减优惠/新用户首单红包? * 新用户是指您的下单设备、手机号、饿了么账号、支付账号都是第一次在饿了么平台使用。以上任意条件不满足,都不能享受新用户优惠。 * 新用户立减优惠、新用户红包、满减特价菜活动不能同时使用。在您首次下单过程中,我们会优先为您选择优惠最大(优惠金额最高)的。 ### Q2: 商品活动规则 * 新用户下首单时,如果用户自己主动退单,则下次不可再享受新用户优惠,如果是商家或客服取消订单,则可以再次享受新用户优惠。 * 6.0版本(含)之前的所有版本,用户在下单时不再享受任何优惠(包含新用户、在线满减、商品折扣、红包等)。 * 移动端所有活动,相同手机号或设备每天只限3单,超过3单收取原价。 * 每个订单最多享受3份活动优惠,超过3份的其余商品收取原价。 * 下单手机号和所选择下单的商家不在同一城市,不享受优惠活动。 * 配送费不计入满减活动的门槛。 ### Q3: 我第一次在 "A" 商家下单,"A" 商家有参加「新用户」活动,我为什么享受不到新用户的立减优惠? * 活动中的新用户指的是饿了么网站的新用户,而不是指 "A" 商家的新客户。如果您不符合饿了么网站新用户的定义则无法享受于新用户相关的活动优惠。 ',
4 | anonymousBuyCaption: "匿名购买",
5 | anonymousBuyContent: "",
6 | awesomeRestaurantCaption: "超赞商家",
7 | awesomeRestaurantContent: "# 超赞商家",
8 | balanceCaption: "余额问题",
9 | balanceContent: "### Q1: 使用余额的条件 为了保护账户安全,使用余额前必须先绑定手机号。 ### Q2: 余额可以怎么用? 余额可以在饿了么平台上提现,当余额大于等于待支付金额时可以在支持在线支付的商家中进行消费。提现功能将于2016年12月25日00:00全面开放。 ### Q3:我要如何提现? 为了保护账户和资金安全,您在提现前需要输入真实姓名和用该姓名开通的银行卡号、选择开户行,并验证已绑定饿了么账号的手机号。每日只能提现1次,每次限额50元。若提现金额超过50元,点击【提现】时系统会提示您已超额,请您修改提现金额。 ### Q4:为什么会提现失败? 可能原因有:您的姓名、开户行、银行卡号等信息不匹配;您当日的提现次数和金额超过限制;您的账户存在异常,被风控拦截。 ",
10 | businessCaption: "商务合作",
11 | businessContent: '### 品牌合作 marketing_coop@ele.me ### 媒体合作 pr@ele.me',
12 | couponCaption: "代金券说明",
13 | couponContent: "### Q1: 什么是商家代金券? 商家代金券是指由商家自己发放代金券,只限在指定的商家使用,可根据条件抵扣相应金额。 ### Q2: 怎么获得商家代金券? * 进入有「进店领券」或「下单返券」标示的商家即有机会获得代金券。 * 「下单返券」需要在指定商家完成满足返券金额要求的订单后才会返还,代金券可在下次下单时使用。 ### Q3: 商家代金券使用条件 * 商家代金券仅限在指定商家使用 * 商家代金券仅限在线支付使用 * 每个订单只能使用一张商家代金券,不可与其他代金券叠加使用",
14 | disclaimerCaption: "免责声明",
15 | disclaimerContent: "# Disclaimer: The application developed by Ele.me or have. Ele.me makes it clear that, your business activities through the participation of the software have nothing to do with Apple Inc., and Apple does not assume any responsibilities of the program. Mobile phone brand partners from Ele.me, such as Apple and App Store. Sponsors of non-mobile phone clients from Ele.me, nor do you get the mobile phone client’s intellectual property rights or any other rights. If the mobile phone client violates the third party’s intellectual property rights, Ele.me will bears the corresponding legal responsibility. Ele.me has the right but not the obligation to improve or correct any errors or defects. Ele.me will not represent or warrant the accuracy or reliability of any contents,information or advertisements which users obtain from the application. Moreover, Ele.me will not be responsible for any products or information which users purchase by the mobile client. Users shall use the application at their own risk. # 免责声明: 本应用由饿了么开发或拥有。饿了么在此申明,用户通过本软件参加的商业活动,与Apple Inc.无关,Apple不承担该程序的任何责任。 饿了么手机客户端的品牌合作商,如Apple,AppStore,非饿了么手机客户端的赞助商,也未拥有该客户端的知识产权或其他任何权益。因饿了么手机客户端侵犯第三方知识产权的,由饿了么承担相应的法律责任。 饿了么有权但无义务,改善或更正本手机客户端的任何错误或缺陷。 用户通过饿了么手机客户端及其中的任何链接、下载获得的一切信息、内容或广告,饿了么不声明或保证其正确性或可靠性;并且对于用户经本手机客户端上的展示、内容、广告而购买、取得的任何产品、或信息,饿了么不负保证责任。用户自行承担使用本软件的风险。",
16 | discountCaption: "优惠说明",
17 | discountContent: '### Q1: 我是新用户,为什么不能享受新用户下单立减优惠/新用户首单红包? * 新用户是指您的下单设备、手机号、饿了么账号、支付账号都是第一次在饿了么平台使用。以上任意条件不满足,都不能享受新用户优惠。 * 如果监测到您不满足以上的信用条件,您的订单将被系统拦截或无偿取消。 * 新用户立减优惠、新用户红包、满减特价菜活动不能同时使用。在您首次下单过程中,我们会优先为您选择优惠最大(优惠金额最高)的。 ### Q2: 首单被取消,再次下单还能享受新用户立减优惠/新用户红包吗? * 您主动取消或商家、骑手取消的订单,饿了么会返还您的新用户资格,这时您仍然可以享受新用户的优惠。 * 您被取消的首单因为「使用的支付账户曾下过单」,必须更换新的支付账户才可以享受新用户优惠。 * 但您取消的原因是账户异常等原因,则不能享受新用户优惠。 ### Q3: 我第一次在 "A" 商家下单,"A" 商家有参加「新用户」活动,我为什么享受不到新用户的立减优惠? * 活动中的新用户指的是饿了么网站的新用户,而不是指 "A" 商家的新客户。如果您不符合饿了么网站新用户的定义则无法享受于新用户相关的活动优惠。 ### Q4: 一个红包能拆开多次使用吗? * 不能,一个红包只能一次性使用,不能分开使用。 ### Q5: 下单的时候使用了红包,但是后来订单取消了,红包还会返还吗? * 会的,订单无效后红包会自动返还到您的账户里。 ### Q6: 红包兑换码怎样兑换成红包,怎样查看红包? * 在个人中心 > 我的红包 > 兑换红包,输入兑换码进行兑换。 ### Q7: 在线支付订单取消后,钱怎么返还? * 使用饿了么账户余额支付,订单无效后,所有款项将退到您的饿了么账户;使用第三方支付订单无效后,支付款项将于2个工作日内返还到您的第三方支付账户,红包退还到饿了么账户。 ### Q8: 每天限制优惠3单,前面下了一个在线支付的单子,由于未付款,订单自动取消了,这单会计算我的参与活动次数吗? * 不会。未付款的订单不会计入您使用优惠的次数。 ### Q9: 每天红包使用次数有限制吗? * 同一个手机号每天最多能使用两个红包优惠(不含预订早餐和预订午餐),使用红包的订单出现退单情况不计入限制。 ',
18 | forgotCaption: "补签规则",
19 | forgotContent: "### 如何补签? 如忘记签到,可通过下单补签,漏签当日至红包领取日前一天每1笔有效订单可补签 1 天(仅限在线支付订单),例:如您在活动第 3 天忘记签到,只要你在第 3 天至第 9 天内完成1笔有效的订单,即可完成补签。",
20 | freshmanCaption: "活动细则",
21 | freshmanContent: "* 新用户是根据设备、饿了么账号、下单手机号进行判断,如果您下单时以上信息均为首次使用则符合饿了么定义的新用户 * 仅限新用户使用移动端app提交订单并选择在线支付时享受(饿配送订单选择餐到付款也可享受) * 在本设备上曾经有过购买记录行为的手机不能参加本活动 * 新用户首单立减金额各区域不同 * 活动仅支持手机客户端最新版本",
22 | hongbaoCaption: "红包问题",
23 | hongbaoContent: "### Q1: 怎么获得红包? * 抢微信朋友分享的红包获得; * 玩游戏领红包(仅限Android客户端); ### Q2: 红包如何使用? * 红包仅限订单选择在线支付时使用; * 每个订单限使用一个红包,每天最多可使用2个红包; * 每个红包只能使用一次,不能叠加或拆分使用; * 红包如有使用金额门槛,则购物车金额需满足金额门槛才可使用; * 红包如有品类、商家、手机号或时段限制,订单需满足对应条件后才可使用; * 红包使用不设找零,如红包可抵扣金额大于订单金额,则订单需支付0.01元。 ### Q3: 下单的时候使用了红包,但是后来订单取消了,红包还会返还吗? * 会的,订单无效后红包会自动返还到您的账户里。 ### Q4: 红包兑换码怎样兑换成红包,怎样查看红包? * 在个人中心 > 我的红包 > 兑换红包,输入兑换码进行兑换。 ### Q5: 预订早餐、预订午餐的红包怎么使用?在哪里查询? * 预订早餐、预订午餐的红包暂时不支持直接点外卖使用,并且当前点外卖的红包也暂时不支持在预订早餐、预订午餐时使用。 * 预订早餐、预订午餐的红包从APP首页点击“预订早餐”按钮进入后在右上角的个人中心中查找预订早餐、预订午餐的红包。 ### Q6: 互斥红包怎么使用? * 互斥红包不与其他优惠活动(包含但不限于:新用户专享、满X元减X元、满X元赠XX)同时使用。 ### Q7: 红包领取规则是什么? * 同一个手机号一天限领取三个。 * 同一注册用户一天限领取三个。 * 注册用户红包直接发送至用户账户里。 * 同一个手机号一天最多使用两个红包。 * 未收到红包短信的用户注意查看手机里的拦截短信。 * 有任何问题请拨打客服电话:10105757。 ### Q8:首单红包的使用条件? * 首单红包需同时满足以下条件才可用,且首单红包不与其他优惠(首减、满减、满赠、套餐赠、折扣菜)同享。 * 新用户(设备、手机号、饿了么账号、支付账号均未在饿了么外卖下过单)首次下单。 * 仅限在线支付使用,且收餐人手机号、领取红包时输入的手机号和账号中的手机号需为同一手机号。 * 微信小程序中“商超便利”和“果蔬生鲜”分类暂未开通。 ",
24 | index: "payment,balance,hongbao,pointtext,member,activity,other",
25 | memberCaption: "会员问题",
26 | memberContent: "### 会员权益调整 尊敬的用户,随着会员服务体系优化,「蜂鸟专送」商家得到大规模普及,大大丰富了会员用户的用餐选择,从2016年9月1日开始,新购及续费的会员服务将由免配送费调整为每单最高减免4元配送费,之前购买的会员服务不受影响,感谢您的支持!敬请期待更多会员特权。 ### Q1: 特权介绍 * 减配送费:饿了么会员卡绑定账户,每日前3单在「蜂鸟专送」标识商家可减配送费,每单最高可减4元。 * 更多特权,敬请期待! ### Q2: 会员资费 * 月卡20元(一个月按31天计算) ### Q3: 购卡说明 * 在线购买:饿了么App > 我的 > 饿了么会员卡。 * 请认准饿了么官方认证渠道,任何从其他第三方途径获得的会员卡,饿了么不保证其可用性。",
27 | memberFullCutCaption: "会员说明",
28 | memberFullCutContent: "### Q1: 特权介绍 * 免配送费:饿了么会员卡绑定账户,每日前3单在「蜂鸟专送」标识商家免配送费。 * 更多特权,敬请期待! ### Q2: 温馨提示 * 用户在当前会员服务失效前,无法购买新卡。 * 请认准饿了么官方渠道,任何从其他第三方途径获得的会员卡,饿了么不保证其可用性。",
29 | memberPartCutCaption: "会员说明",
30 | memberPartCutContent: "### Q1: 特权介绍 * 减免配送费: 饿了么会员卡绑定账户,每日前3单在「蜂鸟专送」标识商家可减免配送费,每单最高可减免4元。 * 更多特权,敬请期待! ### Q2: 温馨提示 * 用户在当前会员服务失效前,无法购买新卡。 * 请认准饿了么官方渠道,任何从其他第三方途径获得的会员卡,饿了么不保证其可用性。",
31 | memberTimesCaption: "会员说明",
32 | memberTimesContent: "> 尊敬的用户,随着会员体系逐渐完善,自2016年10月10日起,饿了么会员权益将做如下优化: 购卡后31天内,累积享有30单减免配送费服务(每日最多3单,每单最高减免4元)。 > 注:已购买的会员服务不受影响,当前会员服务失效前无法购买新卡。 ### Q1: 特权介绍 * 身份标识:饿了么会员服务有效期内,享有专属皇冠标识。 * 减免配送费: 饿了么会员卡自绑定账户之日起31天内,在「蜂鸟专送」标识商家下单,享有30次减免配送费特权,每日最多减免3单,每单最高可减4元。 * 更多特权,敬请期待! ### Q2: 资费介绍 * 饿了么会员卡:20元 ### Q3: 使用说明 当用户满足以下任一条件,会员服务自动失效: 1. 自绑定之日起超过31天; 2. 在31天内累计使用减免配送费的蜂鸟订单数量达到30单; ### Q4: 购卡说明 * 在线购买:饿了么App>我的>饿了么会员卡 ### Q5: 温馨提示 * 用户在当前会员服务失效前,无法购买新卡。 * 请认准饿了么官方渠道,任何从其他第三方途径获得的会员卡,饿了么不保证其可用性。",
33 | ontimeCaption: "准时达问题",
34 | ontimeContent: "### Q1: 准时达规则: 饿了么用户在饿了么App带有「准时达」标签的商家下单,若商品送达时间超过承诺送达时间10分钟,我们将为您赔付一个无门槛红包。 ### Q2: 关于准时达的特殊情况: a. 预订单暂不参加赔付; b. 夜间部分时段下单暂不参加赔付; c. 恶劣天气(雨、雪等)暂不参加赔付; d. 每位用户每天最多赔付3个红包; ### Q3: 常见问题Q&A Q1:我怎么收到赔付红包? A1:当确认送达商品时已超过承诺送达时间10分钟,我们将向您的饿了么账户发放一个无门槛红包,同时会有短信通知到您的手机号码。 ### 饿了么保留法律允许范围内对活动的解释权",
35 | otherCaption: "其它问题",
36 | otherContent: "### Q1: 什么是订单数 订单数是指商家最近30天的订单总数,这个数据是动态的,每天都会进行更新。 ### Q2: 商品多久内可以评价?评价后是否能修改? * 下单确认收货后,7天内可以对商品进行评价。超过7天,评价功能自动失效。 * 美食一旦点评就不能做修改,评价不可删除撤销,请知悉。 ### Q3: 为什么提示下单次数过多,无法下单? 在24小时内,同一手机号在同一设备上最多可以成功提交7次订单。",
37 | paymentCaption: "支付问题",
38 | paymentContent: "### Q1: 使用余额支付不了? 先确认下您的饿了么账户是否有绑定手机号,使用余额支付必须先绑定手机号。 ### Q2: 在线支付订单取消后,钱怎么返还? 使用饿了么账户余额支付(包括:余额、余额+红包),订单无效后,所有款项(包括红包)将退到您的饿了么账户;使用第三方支付(包括:第三方支付、第三方支付+红包),订单无效后,支付款项将于2个工作日内返还到您的第三方支付账户,红包退还到饿了么账户。 ### Q3: 在线支付的过程中,订单显示未支付成功,款项却被扣了,怎么办? 该问题属于第三方(银行/支付宝/微信等)数据传输延迟问题。您可以再等待一下, 如果超过半个小时,订单还是未支付状态,第三方会把款项返还到您的付款账户。具体到账时间依银行而定,一般会在2个工作日内。 ### Q4: 每天限制优惠3单,前面下了一个在线支付的单子,由于未付款,订单自动取消了,这单会计算我的参与活动次数吗? 不会,您可以在「订单列表页」或者「订单详情页」查看,当订单状态变为「订单已取消」时,系统会自动将您之前享受的优惠返还到您的账户中,下一次下单依然可以使用。自己取消订单、超时未付款自动取消订单、商家取消订单,这些情况都会返还优惠次数。 ### Q5: 饿了么账户里的款项怎么提现? 在个人中心 > 我的余额 > 提现处进行提现操作。操作日起2个工作日内,款项会返还至您最近消费过的账户中。 ### Q6: 支付宝免密支付功能如何使用? 首次进入支付收银台并使用支付宝支付时,系统会默认进入免密支付签约页面,您可以根据自身支付喜好选择是否签约免密支付功能。如您不签约该功能,之后会默认使用正常支付宝支付流程。此外,您还可以通过“个人中心”-“小额免密支付”中的免密支付开关,随时进行“签约”、“解约”支付宝免密支付操作。",
39 | phototutorialCaption: "教我拍大片",
40 | phototutorialContent: " ## 1. 清晰 拍照时持稳手机,避免出现大幅度晃动。将焦点对准食物本身,锁焦后、点击快门。
 ## 2. 光线 尽量选择明亮、柔和的光线,避免强光直射;拍摄时避免身体或器物的阴影遮住食物本身,有条件时,可以用小型手电进行补光,以提高食物质感。
 ## 3. 构图 构图可以选择通用的三分构图法或中心构图法,如果是拍摄整体食物时,需要考虑食物的完整性;如果拍摄特写时,需要将细节体现清楚。
 ## 4.角度 可以选择45度拍摄、90度俯拍或者水平拍摄,一切都看你的心情哦~
 ## 5. 背景 可以选择合适的背景拍摄,例如黑色能体现食物蒸腾的热气,白色让食物更有质感,米色更加温馨等;但背景尽量不要太乱,以免影响整体效果。
 ## 6. 细节 餐具的搭配使用、人物的烘托、道具的陪衬等都能使食物更具诱惑力,照片更有氛围。",
41 | pointtextCaption: "积分问题",
42 | pointtextContent: "### Q1: 怎么获得积分? 在线支付的订单将获得订单积分奖励: * 积分将在用户完成评价后获得,会根据订单实际支付金额和评价的质量发放。 * 每位用户每天最多可以获得2000积分,体验商家的订单和评价不会增加积分。 ### Q2: 积分用来做什么? 可以在积分商城兑换各种礼品。 ### Q3: 礼品兑换很多天了还没有收到,该怎么办? 礼品从兑换日起,3个工作日(周末不算)内处理发货,发货后,通常会在3个工作日左右送达。 ### Q4: 礼品兑换中的手机充值卡兑换,怎么样进行充值,充值之前会和我电话确认嘛? 不会,手机充值卡兑换,是直接充值到您填写的手机号上,充值之前不会和您电话确认,所以您在填写电话的时候,请确认电话是否正确。",
43 | rankCaption: "用户等级说明",
44 | rankContent: "用户等级是你在饿了么的身份表现,为了感谢您长期以来对饿了么的信赖和支持,我们会根据你的等级回馈相应福利和特权,功能还在内测中,暂定规则如下: ### 用户等级的划分: 用户等级按月度计算,每个自然月的最后一天会统计你当月的累计消费金额(限在线支付金额,不包含活动优惠及红包及代金券抵扣),决定你次月的等级,具体要求如下。 * Lv0 月累计消费100元以下; * Lv1 月累计消费大于等于100,小于200元 * Lv2 月累计消费大于等于200,小于500元 * Lv3 月累计消费大于等于500 ### 升级及降级规则: 每笔订单完成后,系统会自动计算你当月有效的消费金额(限在线支付金额,不包含活动优惠及红包及代金券抵扣),当月累计消费一旦达到下一等级要求,我们会立刻为您升级,您即时就可享受新等级的相关权益。 如你本月累计消费金额未达到当前等级要求,次月你将被降到与本月消费相匹配的对应等级。 *内测期间饿了么会调整等级权益及规则,饿了么保留对等级体系的所有解释权",
45 | signCaption: "签到规则",
46 | signContent: "### 如何签到领红包 用户需要支付 1 元参与活动(后续签到不收费) 活动期间每日签到,9 天后即可领取 10 元无门槛红包 如期间忘记签到,可领红包金额会减少,详细如下: - **完成 9 天签到:**10元(2个5元红包) - **漏签 1 天:**8元(2个4元红包) - **漏签 2 天:**6元(2个3元红包) - **漏签 3 天:**4元(2个2元红包) - **漏签 4 天及以上:**1个2元红包 ### 漏签后如何补签 如忘记签到,可通过下单补签,漏签当日至红包领取日前一天每1笔有效订单可补签 1 天(仅限在线支付订单),例:如您在活动第 3 天忘记签到,只要你在第 3 天至第 9 天内完成1笔有效的订单,即可完成补签。 ### 每日签到拿福利: - 签到期间,每日 10:30 可抢 5 元红包,每日限领取 1个。红包数量有限,抢完即止,要记得来早哦~",
47 | supervipCaption: "超级会员权益说明",
48 | supervipContent: "## 什么是超级会员 超级会员是饿了么为了更好服务用户,推出的一项增值会员服务,包含众多会员专属权益,全面提升核心用户购物体验,加入会员后您将获得以下会员特权: ### 专享红包 * 当月购买当月生效,可立即获得4张面额5元的饿了么红包,总计20元; * 发放的4个红包皆无使用金额要求,全品类通用(早餐及帮买帮送等特殊订单除外); * 其中有2个红包限蜂鸟专送使用,其余红包无配送要求; * 发放的红包使用日期有区别,相隔14天,也就是有2个红包发放日当日即可使用,有2个需14天后才能使用。 ### 下单奖励 * 每完成5笔在线支付订单,更可领取5元红包,下单越多可领取的红包越多! * 奖励的红包无使用金额要求,全品类通用(早餐及帮买帮送订单除外)。 ### 专属活动 * 针对会员不定期会推出专属活动,可享受会员折扣商品,可获得专属红包及商家代金券等活动。 ### 积分特权 * 积分商城的会员专区将为超级会员不定期推出专属礼品,优惠多多,豪礼多多! ## 常见问题 ### 超级会员是否有配送费优惠? * 超级会员暂无配送费优惠政策,配送费按商家定价收取。 ### 为何没收到会员专享红包? * 专享红包按月发放,如用户购买多月会员,则每月会员生效日可获得对应的4个专享红包。 ### 如何获得下单奖励红包? * 会员有效期内,用户每完成5笔在线支付订单,用户可去会员主页领取5元红包,如会员已过期,则无法领取。 ### 超级会员如何退订? * 会员到期后,如用户不再续费则自动退订,会员有效期内无法退订会员,已缴纳的会费不能返还。 ### 红包有无使用限制? * 专享红包及下单奖励红包无金额门槛要求,但每笔订单需最少支付0.01元,如抵扣金额小于红包金额,则需支付0.01元; * 每个红包只能使用一次,不能叠加或拆分使用; * 红包需在有效期内使用,过期红包即刻失效,请注意红包有效期; * 每月专享红包中,有2个红包有配送限制,订单需为蜂鸟专送方可使用,其余红包无配送限制。 "
49 | }
--------------------------------------------------------------------------------
/app/InitData/hongbao.js:
--------------------------------------------------------------------------------
1 | module.exports = [{
2 | id: 7160761341773,
3 | sn: "201705211244186655961161757573",
4 | user_id: 186655961,
5 | amount: 2,
6 | sum_condition: 40,
7 | name: "分享红包",
8 | phone: "13681711254",
9 | begin_date: "2017-05-21",
10 | end_date: "2017-05-23",
11 | description_map: {
12 | phone: "限收货手机号为 13681711254",
13 | online_paid_only: "限在线支付使用",
14 | validity_delta: "剩3日",
15 | validity_periods: "2017-05-23到期",
16 | sum_condition: "满 40 元可用"
17 | },
18 | limit_map: {},
19 | status: 0,
20 | present_status: 1,
21 | share_status: 0,
22 | schema: "eleme://restaurants?target_name=%E9%99%84%E8%BF%91%E5%95%86%E5%AE%B6&target=%7B%7D"
23 | },
24 | {
25 | id: 7160771283789,
26 | sn: "201705211244186655961313417766",
27 | user_id: 186655961,
28 | amount: 1,
29 | sum_condition: 20,
30 | name: "分享红包",
31 | phone: "13681711254",
32 | begin_date: "2017-05-21",
33 | end_date: "2017-05-23",
34 | description_map: {
35 | phone: "限收货手机号为 13681711254",
36 | online_paid_only: "限在线支付使用",
37 | validity_delta: "剩3日",
38 | validity_periods: "2017-05-23到期",
39 | sum_condition: "满 20 元可用"
40 | },
41 | limit_map: {},
42 | status: 0,
43 | present_status: 1,
44 | share_status: 0,
45 | schema: "eleme://restaurants?target_name=%E9%99%84%E8%BF%91%E5%95%86%E5%AE%B6&target=%7B%7D"
46 | },
47 | {
48 | id: 7160754582349,
49 | sn: "201705211243186655961753696656",
50 | user_id: 186655961,
51 | amount: 4.5,
52 | sum_condition: 30,
53 | name: "分享红包",
54 | phone: "13681711254",
55 | begin_date: "2017-05-21",
56 | end_date: "2017-05-23",
57 | description_map: {
58 | phone: "限收货手机号为 13681711254",
59 | online_paid_only: "限在线支付使用",
60 | validity_delta: "剩3日",
61 | validity_periods: "2017-05-23到期",
62 | sum_condition: "满 30 元可用"
63 | },
64 | limit_map: {
65 | restaurant_flavor_ids: "限品类:快餐便当、特色菜系、小吃夜宵、甜品饮品、异国料理"
66 | },
67 | status: 0,
68 | present_status: 1,
69 | share_status: 0,
70 | schema: "eleme://restaurants?target_name=%E5%BF%AB%E9%A4%90%E4%BE%BF%E5%BD%93%E7%89%B9%E8%89%B2%E8%8F%9C%E7%B3%BB%E5%B0%8F%E5%90%83%E5%A4%9C%E5%AE%B5%E7%94%9C%E5%93%81%E9%A5%AE%E5%93%81%E5%BC%82%E5%9B%BD%E6%96%99%E7%90%86&target=%7B%22category_schema%22%3A%7B%22is_show_all_category%22%3Atrue%2C%22complex_category_ids%22%3A%5B207%2C220%2C233%2C239%2C260%5D%2C%22category_name%22%3A%22%5Cu5feb%5Cu9910%5Cu4fbf%5Cu5f53%5Cu7279%5Cu8272%5Cu83dc%5Cu7cfb%5Cu5c0f%5Cu5403%5Cu591c%5Cu5bb5%5Cu751c%5Cu54c1%5Cu996e%5Cu54c1%5Cu5f02%5Cu56fd%5Cu6599%5Cu7406%22%7D%7D"
71 | },
72 | {
73 | id: 7114345941837,
74 | sn: "201705180135186655961227785920",
75 | user_id: 186655961,
76 | amount: 5,
77 | sum_condition: 24,
78 | name: "普通红包",
79 | phone: "13681711254",
80 | begin_date: "2017-05-18",
81 | end_date: "2017-05-20",
82 | description_map: {
83 | phone: "限收货手机号为 13681711254",
84 | online_paid_only: "限在线支付使用",
85 | validity_delta: "-3天后可用",
86 | validity_periods: "2017-05-20到期",
87 | sum_condition: "满 24 元可用"
88 | },
89 | limit_map: {},
90 | status: 0,
91 | present_status: 4,
92 | share_status: 0
93 | },
94 | {
95 | id: 7114345943885,
96 | sn: "201705180135186655961682785933",
97 | user_id: 186655961,
98 | amount: 4,
99 | sum_condition: 18,
100 | name: "普通红包",
101 | phone: "13681711254",
102 | begin_date: "2017-05-18",
103 | end_date: "2017-05-20",
104 | description_map: {
105 | phone: "限收货手机号为 13681711254",
106 | online_paid_only: "限在线支付使用",
107 | validity_delta: "-3天后可用",
108 | validity_periods: "2017-05-20到期",
109 | sum_condition: "满 18 元可用"
110 | },
111 | limit_map: {
112 | restaurant_flavor_ids: "限品类:果蔬生鲜、商店超市"
113 | },
114 | status: 0,
115 | present_status: 4,
116 | share_status: 0
117 | },
118 | {
119 | id: 7114345944909,
120 | sn: "201705180135186655961379164125",
121 | user_id: 186655961,
122 | amount: 5,
123 | sum_condition: 25,
124 | name: "普通红包",
125 | phone: "13681711254",
126 | begin_date: "2017-05-18",
127 | end_date: "2017-05-20",
128 | description_map: {
129 | phone: "限收货手机号为 13681711254",
130 | online_paid_only: "限在线支付使用",
131 | validity_delta: "-3天后可用",
132 | validity_periods: "2017-05-20到期",
133 | sum_condition: "满 25 元可用"
134 | },
135 | limit_map: {
136 | restaurant_flavor_ids: "限品类:小吃夜宵",
137 | time_periods: "限时段:21:00 - 02:00"
138 | },
139 | status: 0,
140 | present_status: 4,
141 | share_status: 0
142 | },
143 | {
144 | id: 6988252000077,
145 | sn: "201705110124186655961361787430",
146 | user_id: 186655961,
147 | amount: 5,
148 | sum_condition: 25,
149 | name: "普通红包",
150 | phone: "13681711254",
151 | begin_date: "2017-05-11",
152 | end_date: "2017-05-13",
153 | description_map: {
154 | phone: "限收货手机号为 13681711254",
155 | online_paid_only: "限在线支付使用",
156 | validity_delta: "-10天后可用",
157 | validity_periods: "2017-05-13到期",
158 | sum_condition: "满 25 元可用"
159 | },
160 | limit_map: {},
161 | status: 0,
162 | present_status: 4,
163 | share_status: 0
164 | },
165 | {
166 | id: 6988252001101,
167 | sn: "201705110124186655961722477791",
168 | user_id: 186655961,
169 | amount: 4,
170 | sum_condition: 18,
171 | name: "普通红包",
172 | phone: "13681711254",
173 | begin_date: "2017-05-11",
174 | end_date: "2017-05-13",
175 | description_map: {
176 | phone: "限收货手机号为 13681711254",
177 | online_paid_only: "限在线支付使用",
178 | validity_delta: "-10天后可用",
179 | validity_periods: "2017-05-13到期",
180 | sum_condition: "满 18 元可用"
181 | },
182 | limit_map: {
183 | restaurant_flavor_ids: "限品类:果蔬生鲜、商店超市"
184 | },
185 | status: 0,
186 | present_status: 4,
187 | share_status: 0
188 | },
189 | {
190 | id: 6988252002125,
191 | sn: "201705110124186655961378209054",
192 | user_id: 186655961,
193 | amount: 5,
194 | sum_condition: 25,
195 | name: "普通红包",
196 | phone: "13681711254",
197 | begin_date: "2017-05-11",
198 | end_date: "2017-05-13",
199 | description_map: {
200 | phone: "限收货手机号为 13681711254",
201 | online_paid_only: "限在线支付使用",
202 | validity_delta: "-10天后可用",
203 | validity_periods: "2017-05-13到期",
204 | sum_condition: "满 25 元可用"
205 | },
206 | limit_map: {
207 | restaurant_flavor_ids: "限品类:小吃夜宵",
208 | time_periods: "限时段:21:00 - 23:59"
209 | },
210 | status: 0,
211 | present_status: 4,
212 | share_status: 0
213 | },
214 | {
215 | id: 6826679667533,
216 | sn: "201705040218186655961404756960",
217 | user_id: 186655961,
218 | amount: 5,
219 | sum_condition: 25,
220 | name: "普通红包",
221 | phone: "13681711254",
222 | begin_date: "2017-05-04",
223 | end_date: "2017-05-06",
224 | description_map: {
225 | phone: "限收货手机号为 13681711254",
226 | online_paid_only: "限在线支付使用",
227 | validity_delta: "-17天后可用",
228 | validity_periods: "2017-05-06到期",
229 | sum_condition: "满 25 元可用"
230 | },
231 | limit_map: {},
232 | status: 0,
233 | present_status: 4,
234 | share_status: 0
235 | },
236 | {
237 | id: 6826679668557,
238 | sn: "201705040218186655961625497972",
239 | user_id: 186655961,
240 | amount: 4,
241 | sum_condition: 18,
242 | name: "普通红包",
243 | phone: "13681711254",
244 | begin_date: "2017-05-04",
245 | end_date: "2017-05-06",
246 | description_map: {
247 | phone: "限收货手机号为 13681711254",
248 | online_paid_only: "限在线支付使用",
249 | validity_delta: "-17天后可用",
250 | validity_periods: "2017-05-06到期",
251 | sum_condition: "满 18 元可用"
252 | },
253 | limit_map: {
254 | restaurant_flavor_ids: "限品类:果蔬生鲜"
255 | },
256 | status: 0,
257 | present_status: 4,
258 | share_status: 0
259 | },
260 | {
261 | id: 6826679669581,
262 | sn: "201705040218186655961724208735",
263 | user_id: 186655961,
264 | amount: 4,
265 | sum_condition: 20,
266 | name: "普通红包",
267 | phone: "13681711254",
268 | begin_date: "2017-05-04",
269 | end_date: "2017-05-06",
270 | description_map: {
271 | phone: "限收货手机号为 13681711254",
272 | online_paid_only: "限在线支付使用",
273 | validity_delta: "-17天后可用",
274 | validity_periods: "2017-05-06到期",
275 | sum_condition: "满 20 元可用"
276 | },
277 | limit_map: {
278 | restaurant_flavor_ids: "限品类:超市便利店"
279 | },
280 | status: 0,
281 | present_status: 4,
282 | share_status: 0
283 | },
284 | {
285 | id: 6776347937613,
286 | sn: "201705020237186655961587770680",
287 | user_id: 186655961,
288 | amount: 5,
289 | sum_condition: 25,
290 | name: "普通红包",
291 | phone: "13681711254",
292 | begin_date: "2017-05-02",
293 | end_date: "2017-05-04",
294 | description_map: {
295 | phone: "限收货手机号为 13681711254",
296 | online_paid_only: "限在线支付使用",
297 | validity_delta: "-19天后可用",
298 | validity_periods: "2017-05-04到期",
299 | sum_condition: "满 25 元可用"
300 | },
301 | limit_map: {},
302 | status: 0,
303 | present_status: 4,
304 | share_status: 0
305 | },
306 | {
307 | id: 6776347939661,
308 | sn: "201705020237186655961281037962",
309 | user_id: 186655961,
310 | amount: 4,
311 | sum_condition: 20,
312 | name: "普通红包",
313 | phone: "13681711254",
314 | begin_date: "2017-05-02",
315 | end_date: "2017-05-04",
316 | description_map: {
317 | phone: "限收货手机号为 13681711254",
318 | online_paid_only: "限在线支付使用",
319 | validity_delta: "-19天后可用",
320 | validity_periods: "2017-05-04到期",
321 | sum_condition: "满 20 元可用"
322 | },
323 | limit_map: {
324 | restaurant_flavor_ids: "限品类:果蔬生鲜"
325 | },
326 | status: 0,
327 | present_status: 4,
328 | share_status: 0
329 | },
330 | {
331 | id: 6776347942733,
332 | sn: "201705020237186655961580452097",
333 | user_id: 186655961,
334 | amount: 4,
335 | sum_condition: 28,
336 | name: "普通红包",
337 | phone: "13681711254",
338 | begin_date: "2017-05-02",
339 | end_date: "2017-05-04",
340 | description_map: {
341 | phone: "限收货手机号为 13681711254",
342 | online_paid_only: "限在线支付使用",
343 | validity_delta: "-19天后可用",
344 | validity_periods: "2017-05-04到期",
345 | sum_condition: "满 28 元可用"
346 | },
347 | limit_map: {
348 | restaurant_flavor_ids: "限品类:超市便利店"
349 | },
350 | status: 0,
351 | present_status: 4,
352 | share_status: 0
353 | },
354 | {
355 | id: 6635705093965,
356 | sn: "201704250238186655961834564160",
357 | user_id: 186655961,
358 | amount: 5,
359 | sum_condition: 25,
360 | name: "普通红包",
361 | phone: "13681711254",
362 | begin_date: "2017-04-25",
363 | end_date: "2017-04-27",
364 | description_map: {
365 | phone: "限收货手机号为 13681711254",
366 | online_paid_only: "限在线支付使用",
367 | validity_delta: "-26天后可用",
368 | validity_periods: "2017-04-27到期",
369 | sum_condition: "满 25 元可用"
370 | },
371 | limit_map: {},
372 | status: 0,
373 | present_status: 4,
374 | share_status: 0
375 | },
376 | {
377 | id: 6635705096013,
378 | sn: "201704250238186655961925708910",
379 | user_id: 186655961,
380 | amount: 4,
381 | sum_condition: 20,
382 | name: "普通红包",
383 | phone: "13681711254",
384 | begin_date: "2017-04-25",
385 | end_date: "2017-04-27",
386 | description_map: {
387 | phone: "限收货手机号为 13681711254",
388 | online_paid_only: "限在线支付使用",
389 | validity_delta: "-26天后可用",
390 | validity_periods: "2017-04-27到期",
391 | sum_condition: "满 20 元可用"
392 | },
393 | limit_map: {
394 | restaurant_flavor_ids: "限品类:果蔬生鲜"
395 | },
396 | status: 0,
397 | present_status: 4,
398 | share_status: 0
399 | },
400 | {
401 | id: 6635705097037,
402 | sn: "201704250238186655961400865908",
403 | user_id: 186655961,
404 | amount: 4,
405 | sum_condition: 28,
406 | name: "普通红包",
407 | phone: "13681711254",
408 | begin_date: "2017-04-25",
409 | end_date: "2017-04-27",
410 | description_map: {
411 | phone: "限收货手机号为 13681711254",
412 | online_paid_only: "限在线支付使用",
413 | validity_delta: "-26天后可用",
414 | validity_periods: "2017-04-27到期",
415 | sum_condition: "满 28 元可用"
416 | },
417 | limit_map: {
418 | restaurant_flavor_ids: "限品类:超市便利店"
419 | },
420 | status: 0,
421 | present_status: 4,
422 | share_status: 0
423 | }
424 | ]
--------------------------------------------------------------------------------
/app/InitData/payments.js:
--------------------------------------------------------------------------------
1 | module.exports = [{
2 | description: "(商家仅支持在线支付)",
3 | disabled_reason: "",
4 | id: 1,
5 | is_online_payment: true,
6 | name: "在线支付",
7 | promotion: [],
8 | select_state: 1,
9 | }, {
10 | description: "(商家不支持货到付款)",
11 | disabled_reason: "商家仅支持在线支付",
12 | id: 2,
13 | is_online_payment: false,
14 | name: "货到付款",
15 | promotion: [],
16 | select_state: -1,
17 | }]
--------------------------------------------------------------------------------
/app/InitData/rate.js:
--------------------------------------------------------------------------------
1 | const ratingList = [{ "avatar": "", "highlights": [], "item_ratings": [{ "food_id": 508807792, "food_name": "超级至尊比萨-铁盘", "image_hash": "dc864033625905f0a15a2d181d53a425jpeg", "is_valid": 1 }, { "food_id": 508808743, "food_name": "韩式浓情风味鸡(标准份)", "image_hash": "074e0e203f613deff4e456c31e4177d1jpeg", "is_valid": 1 }], "rated_at": "2017-02-10", "rating_star": 5, "rating_text": "", "tags": [], "time_spent_desc": "按时送达", "username": "4*******b" }, { "avatar": "15f6cf782b0c9cd5ca8daa7f76ab05aejpeg", "highlights": [], "item_ratings": [{ "food_id": 508809467, "food_name": "香草凤尾虾-5只装", "image_hash": "", "is_valid": 1 }, { "food_id": 508808754, "food_name": "鸡茸蘑菇汤", "image_hash": "5388b26ad173389d89e0e015dbf295fcjpeg", "is_valid": 1 }], "rated_at": "2017-02-09", "rating_star": 5, "rating_text": "", "tags": [], "time_spent_desc": "", "username": "t****n" }, { "avatar": "", "highlights": [], "item_ratings": [{ "food_id": 508809480, "food_name": "冰柠檬红茶(标准份)", "image_hash": "", "is_valid": 1 }], "rated_at": "2017-01-18", "rating_star": 5, "rating_text": "", "tags": [], "time_spent_desc": "", "username": ",******C" }, { "avatar": "", "highlights": [], "item_ratings": [], "rated_at": "2017-02-10", "rating_star": 5, "rating_text": "", "tags": [], "time_spent_desc": "", "username": "试******春" }, { "avatar": "1b523ca27369a0eed1ce0c3fc0a5ba8bjpeg", "highlights": [], "item_ratings": [{ "food_id": 529149980, "food_name": "富贵“鸡”祥大吉大利比萨", "image_hash": "", "is_valid": 1 }, { "food_id": 144654782, "food_name": "热柠檬红茶", "image_hash": "", "is_valid": 1 }], "rated_at": "2017-02-10", "rating_star": 5, "rating_text": "", "tags": [], "time_spent_desc": "", "username": "王******a" }, { "avatar": "", "highlights": [], "item_ratings": [{ "food_id": 508808726, "food_name": "加州风情香烤牛肉比萨-铁盘", "image_hash": "", "is_valid": 1 }, { "food_id": 508810265, "food_name": "海鲜至尊比萨-铁盘", "image_hash": "", "is_valid": 1 }, { "food_id": 508807792, "food_name": "超级至尊比萨-铁盘", "image_hash": "", "is_valid": 1 }], "rated_at": "2017-02-10", "rating_star": 5, "rating_text": "", "tags": [], "time_spent_desc": "", "username": "3*******7" }, { "avatar": "", "highlights": [], "item_ratings": [{ "food_id": 529149980, "food_name": "富贵“鸡”祥大吉大利比萨", "image_hash": "", "is_valid": 1 }, { "food_id": 508808743, "food_name": "韩式浓情风味鸡(标准份)", "image_hash": "", "is_valid": 1 }], "rated_at": "2017-02-10", "rating_star": 5, "rating_text": "", "tags": [], "time_spent_desc": "", "username": "3*******6" }, { "avatar": "818cf0c977c77ca365557230db619a18jpeg", "highlights": [], "item_ratings": [], "rated_at": "2017-02-10", "rating_star": 5, "rating_text": "送餐速度很快!", "tags": [], "time_spent_desc": "", "username": "3*******7" }, { "avatar": "", "highlights": [], "item_ratings": [], "rated_at": "2017-02-10", "rating_star": 5, "rating_text": "", "tags": [], "time_spent_desc": "", "username": "3*******b" }, { "avatar": "", "highlights": [], "item_ratings": [], "rated_at": "2017-02-09", "rating_star": 5, "rating_text": "", "tags": [], "time_spent_desc": "", "username": "景***0" }];
2 |
3 | const scores = { "compare_rating": 0.76869, "deliver_time": 40, "food_score": 4.76378, "order_rating_amount": 473, "overall_score": 4.72836, "service_score": 4.69295 };
4 |
5 | const tags = [{ "count": 473, "name": "全部", "unsatisfied": false }, { "count": 453, "name": "满意", "unsatisfied": false }, { "count": 20, "name": "不满意", "unsatisfied": true }, { "count": 2, "name": "有图", "unsatisfied": false }, { "count": 47, "name": "味道好", "unsatisfied": false }, { "count": 32, "name": "送货快", "unsatisfied": false }, { "count": 18, "name": "分量足", "unsatisfied": false }, { "count": 15, "name": "包装精美", "unsatisfied": false }, { "count": 15, "name": "干净卫生", "unsatisfied": false }, { "count": 15, "name": "食材新鲜", "unsatisfied": false }, { "count": 11, "name": "服务不错", "unsatisfied": false }];
6 |
7 | module.exports = {
8 | ratingList,
9 | scores,
10 | tags
11 | }
--------------------------------------------------------------------------------
/app/InitData/remark.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | remarks: [
3 | [
4 | "不要辣",
5 | "少点辣",
6 | "多点辣"
7 | ],
8 | [
9 | "不要香菜"
10 | ],
11 | [
12 | "不要洋葱"
13 | ],
14 | [
15 | "多点醋"
16 | ],
17 | [
18 | "多点葱"
19 | ],
20 | [
21 | "去冰",
22 | "少冰"
23 | ]
24 | ]
25 | }
--------------------------------------------------------------------------------
/app/controller/admin/admin.js:
--------------------------------------------------------------------------------
1 | const Controller = require('egg').Controller
2 | const md5 = require('blueimp-md5')
3 | const dtime = require('moment')
4 | // const jwt = require('jwt-simple')
5 | // const moment = require('moment')
6 |
7 | class AdminController extends Controller {
8 | // 全部处理放在service,后期再抽象
9 | // POST /admin/login
10 | async login() {
11 | await this.service.admin.admin.login()
12 | }
13 |
14 | // GET /admin/info
15 | async getAdminInfo() {
16 | await this.service.admin.admin.getAdminInfo()
17 | }
18 |
19 | // GET /admin/signout
20 | async signout() {
21 | await this.service.admin.admin.signout()
22 | }
23 |
24 | // GET /admin/all
25 | async getAllAdmin() {
26 | await this.service.admin.admin.getAllAdmin()
27 | }
28 |
29 | // GET /admin/count
30 | async getAdminCount() {
31 | await this.service.admin.admin.getAdminCount()
32 | }
33 |
34 | async register() {
35 | await this.service.admin.admin.register()
36 | }
37 |
38 | async updateAvatar() {
39 | await this.service.admin.admin.updateAvatar()
40 | }
41 |
42 | }
43 |
44 | module.exports = AdminController
--------------------------------------------------------------------------------
/app/controller/member/vipCart.js:
--------------------------------------------------------------------------------
1 | const Controller = require('egg').Controller
2 |
3 | class VipCartController extends Controller {
4 | // 全部处理放在service,后期再抽象
5 | async useCart() {
6 | await this.service.member.vipCart.useCart()
7 | }
8 | }
9 |
10 | module.exports = VipCartController
--------------------------------------------------------------------------------
/app/controller/promotion/hongbao.js:
--------------------------------------------------------------------------------
1 | const Controller = require('egg').Controller
2 |
3 | class HongbaoController extends Controller {
4 | // 全部处理放在service,后期再抽象
5 | async getHongbao() {
6 | await this.service.promotion.hongbao.getHongbao('intime')
7 | }
8 |
9 | async getExpiredHongbao() {
10 | await this.service.promotion.hongbao.getHongbao('expired')
11 | }
12 |
13 | async exchange() {
14 | await this.service.promotion.hongbao.exchange()
15 | }
16 | }
17 |
18 | module.exports = HongbaoController
--------------------------------------------------------------------------------
/app/controller/shopping/category.js:
--------------------------------------------------------------------------------
1 | const Controller = require('egg').Controller
2 |
3 | class CategoryController extends Controller {
4 | // GET /shopping/v2/restaurant/category
5 | async getCategories() {
6 | await this.service.shopping.category.getCategories()
7 | }
8 |
9 | async addCategory() {
10 | await this.service.shopping.category.addCategory()
11 | }
12 |
13 | async findById() {
14 | await this.service.shopping.category.findById()
15 | }
16 |
17 | async getDelivery() {
18 | await this.service.shopping.category.getDelivery()
19 | }
20 |
21 | async getActivity() {
22 | await this.service.shopping.category.getActivity()
23 | }
24 |
25 | }
26 |
27 | module.exports = CategoryController
--------------------------------------------------------------------------------
/app/controller/shopping/food.js:
--------------------------------------------------------------------------------
1 | const Controller = require('egg').Controller
2 |
3 | class FoodController extends Controller {
4 | async initData() {
5 | await this.service.shopping.food.initData()
6 | }
7 |
8 | // GET /shopping/v2/restaurant/category
9 | async getCategory() {
10 | await this.service.shopping.food.getCategory()
11 | }
12 |
13 | // post /shopping/addcategory
14 | async addCategory() {
15 | await this.service.shopping.food.addCategory()
16 | }
17 |
18 | async addFood() {
19 | await this.service.shopping.food.addFood()
20 | }
21 |
22 | async getSpecfoods() {
23 | await this.service.shopping.food.getSpecfoods()
24 | }
25 |
26 | async getMenu() {
27 | await this.service.shopping.food.getMenu()
28 | }
29 |
30 | async getMenuDetail() {
31 | await this.service.shopping.food.getMenuDetail()
32 | }
33 |
34 | async getFoods() {
35 | await this.service.shopping.food.getFoods()
36 | }
37 |
38 | async getFoodsCount() {
39 | await this.service.shopping.food.getFoodsCount()
40 | }
41 |
42 | async updateFood() {
43 | await this.service.shopping.food.updateFood()
44 | }
45 |
46 | async deleteFood() {
47 | await this.service.shopping.food.deleteFood()
48 | }
49 |
50 | }
51 |
52 | module.exports = FoodController
--------------------------------------------------------------------------------
/app/controller/shopping/shop.js:
--------------------------------------------------------------------------------
1 | const Controller = require('egg').Controller
2 |
3 | class ShopController extends Controller {
4 | // POST /shopping/addShop
5 | async addShop() {
6 | await this.service.shopping.shop.addShop()
7 | }
8 |
9 | // GET /shopping/restaurants
10 | async getRestaurants() {
11 | await this.service.shopping.shop.getRestaurants()
12 | }
13 |
14 | async searchResaturant() {
15 | await this.service.shopping.shop.searchResaturant()
16 | }
17 |
18 | async getRestaurantDetail() {
19 | await this.service.shopping.shop.getRestaurantDetail()
20 | }
21 |
22 | // GET /shopping/restaurants/count
23 | async getShopCount() {
24 | await this.service.shopping.shop.getShopCount()
25 | }
26 |
27 | // POST /shopping/updateshop
28 | async updateshop() {
29 | await this.service.shopping.shop.updateshop()
30 | }
31 |
32 | // DELETE /shopping/restaurant/:restaurant_id
33 | async deleteResturant() {
34 | await this.service.shopping.shop.deleteResturant()
35 | }
36 |
37 |
38 | }
39 |
40 | module.exports = ShopController
--------------------------------------------------------------------------------
/app/controller/statis/statis.js:
--------------------------------------------------------------------------------
1 | const Controller = require('egg').Controller
2 |
3 | class StatisController extends Controller {
4 | async apiCount() {
5 | await this.service.statis.statis.apiCount()
6 | }
7 |
8 | async apiAllCount() {
9 | await this.service.statis.statis.apiAllCount()
10 | }
11 |
12 | async allApiRecord() {
13 | await this.service.statis.statis.allApiRecord()
14 | }
15 |
16 | async userCount() {
17 | await this.service.statis.statis.userCount()
18 | }
19 |
20 | async adminCount() {
21 | await this.service.statis.statis.adminCount()
22 | }
23 |
24 | async orderCount() {
25 | await this.service.statis.statis.orderCount()
26 | }
27 |
28 | }
29 |
30 | module.exports = StatisController
--------------------------------------------------------------------------------
/app/controller/ugc/rating.js:
--------------------------------------------------------------------------------
1 | const Controller = require('egg').Controller;
2 |
3 | class RatingController extends Controller {
4 | async initData() {
5 | await this.service.ugc.rating.initData()
6 | }
7 |
8 | async getRatings() {
9 | await this.service.ugc.rating.getRatings()
10 | }
11 |
12 | async getScores() {
13 | await this.service.ugc.rating.getScores()
14 | }
15 |
16 | async getTags() {
17 | await this.service.ugc.rating.getTags()
18 | }
19 |
20 | }
21 |
22 |
23 | module.exports = RatingController;
--------------------------------------------------------------------------------
/app/controller/upload.js:
--------------------------------------------------------------------------------
1 | const Controller = require('egg').Controller
2 |
3 | class UploadController extends Controller {
4 | // POST /addimg/:type
5 | async upload() {
6 | await this.service.upload.upload()
7 | }
8 |
9 | }
10 |
11 | module.exports = UploadController
--------------------------------------------------------------------------------
/app/controller/v1/addre.js:
--------------------------------------------------------------------------------
1 | const Controller = require('egg').Controller
2 |
3 | class AddreController extends Controller {
4 | // 全部处理放在service,后期再抽象
5 | async getAddress() {
6 | await this.service.v1.addre.getAddress()
7 | }
8 |
9 | async addAddress() {
10 | await this.service.v1.addre.addAddress()
11 | }
12 |
13 | async deleteAddress() {
14 | await this.service.v1.addre.deleteAddress()
15 | }
16 |
17 | async getAddAddressById() {
18 | await this.service.v1.addre.getAddAddressById()
19 | }
20 |
21 | }
22 |
23 | module.exports = AddreController
--------------------------------------------------------------------------------
/app/controller/v1/captchas.js:
--------------------------------------------------------------------------------
1 | const Controller = require('egg').Controller;
2 |
3 | class CaptchasController extends Controller {
4 | async getCaptchas() {
5 | await this.service.v1.captchas.getCaptchas()
6 | }
7 | }
8 |
9 |
10 | module.exports = CaptchasController;
--------------------------------------------------------------------------------
/app/controller/v1/carts.js:
--------------------------------------------------------------------------------
1 | const Controller = require('egg').Controller
2 |
3 | class CartsController extends Controller {
4 | // 全部处理放在service,后期再抽象
5 | async checkout() {
6 | await this.service.v1.carts.checkout()
7 | }
8 |
9 | }
10 |
11 | module.exports = CartsController
--------------------------------------------------------------------------------
/app/controller/v1/city.js:
--------------------------------------------------------------------------------
1 | const Controller = require('egg').Controller;
2 | const pinyin = require('pinyin')
3 |
4 | class CityController extends Controller {
5 | async getCity() {
6 | await this.service.v1.city.getCity()
7 | }
8 |
9 | async getCityName() {
10 | await this.service.v1.city.getCityName()
11 | }
12 |
13 | async getCityById() {
14 | await this.service.v1.city.getCityById()
15 | }
16 |
17 | async getExactAddress() {
18 | await this.service.v1.city.getExactAddress()
19 | }
20 |
21 | async pois() {
22 | await this.service.v1.city.pois()
23 | }
24 | }
25 |
26 |
27 | module.exports = CityController;
--------------------------------------------------------------------------------
/app/controller/v1/order.js:
--------------------------------------------------------------------------------
1 | const Controller = require('egg').Controller
2 |
3 | class OrderController extends Controller {
4 | // 全部处理放在service,后期再抽象
5 | async postOrder() {
6 | await this.service.v1.order.postOrder()
7 | }
8 |
9 | async getOrders() {
10 | await this.service.v1.order.getOrders()
11 | }
12 |
13 | async getDetail() {
14 | await this.service.v1.order.getDetail()
15 | }
16 |
17 | async getAllOrders() {
18 | await this.service.v1.order.getAllOrders()
19 | }
20 |
21 | async getOrdersCount() {
22 | await this.service.v1.order.getOrdersCount()
23 | }
24 |
25 | }
26 |
27 | module.exports = OrderController
--------------------------------------------------------------------------------
/app/controller/v1/remark.js:
--------------------------------------------------------------------------------
1 | const Controller = require('egg').Controller
2 |
3 | class RemarkController extends Controller {
4 | // 全部处理放在service,后期再抽象
5 | async getRemarks() {
6 | await this.service.v1.remark.getRemarks()
7 | }
8 |
9 | }
10 |
11 | module.exports = RemarkController
--------------------------------------------------------------------------------
/app/controller/v1/search.js:
--------------------------------------------------------------------------------
1 | const Controller = require('egg').Controller
2 |
3 | class searchController extends Controller {
4 | async search() {
5 | await this.service.v1.search.search()
6 | }
7 |
8 | }
9 |
10 | module.exports = searchController
--------------------------------------------------------------------------------
/app/controller/v2/entry.js:
--------------------------------------------------------------------------------
1 | const Controller = require('egg').Controller
2 |
3 | class EntryController extends Controller {
4 | // 全部处理放在service,后期再抽象
5 | async getEntry() {
6 | await this.service.v2.entry.getEntry()
7 | }
8 | }
9 |
10 | module.exports = EntryController
--------------------------------------------------------------------------------
/app/controller/v2/user.js:
--------------------------------------------------------------------------------
1 | const Controller = require('egg').Controller
2 |
3 | class UserController extends Controller {
4 | // 全部处理放在service,后期再抽象
5 | async login() {
6 | await this.service.v2.user.login()
7 | }
8 |
9 | async getInfo() {
10 | await this.service.v2.user.getInfo()
11 | }
12 |
13 | async getInfoById() {
14 | await this.service.v2.user.getInfoById()
15 | }
16 |
17 | async signout() {
18 | await this.service.v2.user.signout()
19 | }
20 |
21 | async chanegPassword() {
22 | await this.service.v2.user.chanegPassword()
23 | }
24 |
25 | async getUserList() {
26 | await this.service.v2.user.getUserList()
27 | }
28 |
29 | async getUserCount() {
30 | await this.service.v2.user.getUserCount()
31 | }
32 |
33 | async updateAvatar() {
34 | await this.service.v2.user.updateAvatar()
35 | }
36 |
37 | async getUserCity() {
38 | await this.service.v2.user.getUserCity()
39 | }
40 | }
41 |
42 | module.exports = UserController
--------------------------------------------------------------------------------
/app/controller/v3/explain.js:
--------------------------------------------------------------------------------
1 | const Controller = require('egg').Controller
2 |
3 | class ExplainController extends Controller {
4 | // 全部处理放在service,后期再抽象
5 | async getExpalin() {
6 | await this.service.v3.explain.getExpalin()
7 | }
8 | }
9 |
10 | module.exports = ExplainController
--------------------------------------------------------------------------------
/app/extend/helper.js:
--------------------------------------------------------------------------------
1 | // const pinyin = require('pinyin')
2 |
3 | module.exports = {
4 | //获取id列表
5 | async getId(type) {
6 | const ctx = this.ctx
7 | const idList = ['restaurant_id', 'food_id', 'order_id', 'user_id', 'address_id', 'cart_id', 'img_id', 'category_id', 'item_id', 'sku_id', 'admin_id', 'statis_id'];
8 | if (!idList.includes(type)) {
9 | throw new Error('id类型错误');
10 | return
11 | }
12 | try {
13 | const idData = await ctx.model.Ids.findOne();
14 | idData[type]++;
15 | await idData.save();
16 | return idData[type]
17 | } catch (err) {
18 | throw new Error(err)
19 | }
20 | },
21 |
22 | async uploadImg() {
23 |
24 | },
25 |
26 | async getPath() {
27 |
28 | },
29 |
30 | async qiniu() {
31 |
32 | },
33 |
34 | uptoken() {
35 |
36 | },
37 |
38 | uploadFile() {
39 |
40 | }
41 | };
--------------------------------------------------------------------------------
/app/middleware/checkAdmin.js:
--------------------------------------------------------------------------------
1 | module.exports = (options, app) => {
2 | return async function(ctx, next) {
3 | const admin_id = ctx.session.admin_id;
4 | if (!admin_id || !Number(admin_id)) {
5 | ctx.body={
6 | status: 0,
7 | type: 'ERROR_SESSION',
8 | message: '亲,您还没有登录',
9 | }
10 | return
11 | } else {
12 | const admin = await ctx.model.Admin.findOne({ id: admin_id });
13 | if (!admin) {
14 | ctx.body={
15 | status: 0,
16 | type: 'HAS_NO_ACCESS',
17 | message: '亲,您还不是管理员',
18 | }
19 | return
20 | }
21 | }
22 |
23 | // 注意:中间件中调用 next 必须前置 await,否则后续中间件无法继续 await
24 | await next();
25 | };
26 | };
--------------------------------------------------------------------------------
/app/middleware/checkSuperAdmin.js:
--------------------------------------------------------------------------------
1 | module.exports = (options, app) => {
2 | return async function(ctx, next) {
3 | const admin_id = ctx.session.admin_id;
4 | if (!admin_id || !Number(admin_id)) {
5 | ctx.body = {
6 | status: 0,
7 | type: 'ERROR_SESSION',
8 | message: '亲,您还没有登录',
9 | }
10 | return
11 | } else {
12 | const admin = await ctx.model.Admin.findOne({ id: admin_id });
13 | if (!admin || admin.status != 2) {
14 | ctx.body = {
15 | status: 0,
16 | type: 'HAS_NO_ACCESS',
17 | message: '亲,您的权限不足',
18 | }
19 | return
20 | }
21 | }
22 |
23 | // 注意:中间件中调用 next 必须前置 await,否则后续中间件无法继续 await
24 | await next();
25 | };
26 | };
--------------------------------------------------------------------------------
/app/middleware/check_api_token.js:
--------------------------------------------------------------------------------
1 | const jwt = require('jwt-simple');
2 | const moment = require('moment');
3 | module.exports = (options, app) => {
4 | return async function(ctx, next) {
5 | // 尝试从请求头、请求体、查询字符串中获取 token 信息
6 | const token = ctx.get('x-access-token');
7 |
8 | if (!token) {
9 | ctx.status = 400;
10 | return ctx.body = {
11 | error: '请提供请求头 X-Access-Token 信息!',
12 | };
13 | }
14 |
15 | let decodedToken = null;
16 |
17 | // 校验 token 的正确性
18 | try {
19 | decodedToken = jwt.decode(token, 'lipengzhou');
20 | } catch (err) {
21 | validToken = false;
22 | ctx.status = 401;
23 | return ctx.body = {
24 | error: '无效的 token',
25 | };
26 | }
27 |
28 | // 如果 token 无效,则停止后续执行
29 | if (!decodedToken) {
30 | return;
31 | }
32 |
33 | // 如果过期时间小于当前时间,说明已过期
34 | if (decodedToken.exp < moment().valueOf()) {
35 | ctx.status = 401;
36 | return ctx.body = {
37 | error: 'token 已过期,需要重新登陆换取新的 token',
38 | };
39 | }
40 |
41 | // 把用户 id 记录到上下文中方便在后续中间件使用
42 | ctx.user = decodedToken.iss;
43 |
44 | // token 校验通过,进入下一个中间件
45 | // 注意:中间件中调用 next 必须前置 await,否则后续中间件无法继续 await
46 | await next();
47 | };
48 | };
49 |
--------------------------------------------------------------------------------
/app/model/activity.js:
--------------------------------------------------------------------------------
1 | const activityData = require('../InitData/activity')
2 |
3 | module.exports = app => {
4 | const mongoose = app.mongoose
5 |
6 | const activitySchema = new mongoose.Schema({
7 | description: String,
8 | icon_color: String,
9 | icon_name: String,
10 | id: Number,
11 | name: String,
12 | ranking_weight: Number
13 | })
14 |
15 | activitySchema.index({ index: 1 });
16 |
17 | const Activity = mongoose.model('Activity', activitySchema)
18 |
19 | Activity.findOne((err, data) => {
20 | if (!data) {
21 | activityData.forEach(item => {
22 | Activity.create(item);
23 | })
24 | }
25 | })
26 |
27 | return Activity
28 | }
--------------------------------------------------------------------------------
/app/model/address.js:
--------------------------------------------------------------------------------
1 | module.exports = app => {
2 | const mongoose = app.mongoose
3 |
4 | const addressSchema = new mongoose.Schema({
5 | id: Number,
6 | address: String,
7 | phone: String,
8 | user_id: Number,
9 | is_valid: { type: Number, default: 1 },
10 | created_at: { type: Date, default: Date.now() },
11 | phone_bk: String,
12 | tag_type: Number,
13 | name: String,
14 | st_geohash: String,
15 | address_detail: String,
16 | poi_type: { type: Number, default: 0 },
17 | sex: { type: Number, default: 1 },
18 | city_id: { type: Number, default: 1 },
19 | tag: { type: String, default: '家' },
20 | is_user_default: { type: Boolean, default: true },
21 | is_deliverable: { type: Boolean, default: true },
22 | agent_fee: { type: Number, default: 0 },
23 | deliver_amount: { type: Number, default: 0 },
24 | phone_had_bound: { type: Boolean, default: true },
25 | })
26 |
27 | addressSchema.index({ id: 1 });
28 |
29 | return mongoose.model('Address', addressSchema);
30 | }
--------------------------------------------------------------------------------
/app/model/admin.js:
--------------------------------------------------------------------------------
1 | module.exports = app => {
2 | const mongoose = app.mongoose
3 |
4 | const adminSchema = new mongoose.Schema({
5 | username: { // 用户名
6 | type: String,
7 | required: true
8 | },
9 | password: { // 密码
10 | type: String,
11 | required: true
12 | },
13 | id: Number,
14 | create_time: String,
15 | city: String,
16 | status: Number,
17 | admin: {
18 | type: String,
19 | default: '管理员'
20 | },
21 | avatar: {
22 | type: String,
23 | default: 'default.jpg'
24 | },
25 | })
26 |
27 | adminSchema.index({ id: 1 })
28 |
29 | return mongoose.model('Admin', adminSchema)
30 | }
--------------------------------------------------------------------------------
/app/model/cart.js:
--------------------------------------------------------------------------------
1 | module.exports = app => {
2 | const mongoose = app.mongoose
3 | const Schema = mongoose.Schema;
4 |
5 | const cartSchema = new mongoose.Schema({
6 | id: Number,
7 | cart: {
8 | id: Number,
9 | groups: [
10 | [{
11 | attrs: [],
12 | extra: [],
13 | id: Number,
14 | new_specs: [],
15 | name: String,
16 | price: Number,
17 | quantity: Number,
18 | specs: [String],
19 | packing_fee: Number,
20 | sku_id: Number,
21 | stock: Number,
22 | }]
23 | ],
24 | extra: [{
25 | description: String,
26 | name: { type: String, default: '餐盒' },
27 | price: { type: Number, default: 0 },
28 | quantity: { type: Number, default: 0 },
29 | type: { type: Number, default: 0 },
30 | }],
31 | deliver_amount: Number,
32 | deliver_time: String,
33 | discount_amount: String,
34 | dist_info: String,
35 | is_address_too_far: { type: Boolean, default: false },
36 | is_deliver_by_fengniao: Boolean,
37 | is_online_paid: { type: Number, default: 1 },
38 | is_ontime_available: { type: Number, default: 0 },
39 | must_new_user: { type: Number, default: 0 },
40 | must_pay_online: { type: Number, default: 0 },
41 | ontime_status: { type: Number, default: 0 },
42 | ontime_unavailable_reason: String,
43 | original_total: Number,
44 | phone: String,
45 | promise_delivery_time: { type: Number, default: 0 },
46 | restaurant_id: Number,
47 | restaurant_info: Schema.Types.Mixed,
48 | restaurant_minimum_order_amount: Number,
49 | restaurant_name_for_url: String,
50 | restaurant_status: { type: Number, default: 1 },
51 | service_fee_explanation: { type: Number, default: 0 },
52 | total: Number,
53 | user_id: Number,
54 | },
55 | delivery_reach_time: String,
56 | invoice: {
57 | is_available: { type: Boolean, default: false },
58 | status_text: String,
59 | },
60 | sig: String,
61 | current_address: {},
62 | payments: [{
63 | description: String,
64 | disabled_reason: String,
65 | id: Number,
66 | is_online_payment: { type: Boolean, default: true },
67 | name: String,
68 | promotion: [],
69 | select_state: Number,
70 | }],
71 | deliver_times: [],
72 | deliver_times_v2: [],
73 | merchant_coupon_info: {},
74 | number_of_meals: {},
75 | discount_rule: {},
76 | hongbao_info: {},
77 | is_support_coupon: { type: Boolean, default: false },
78 | is_support_ninja: { type: Number, default: 1 },
79 | })
80 |
81 | cartSchema.index({ id: 1 });
82 |
83 | return mongoose.model('Cart', cartSchema)
84 | }
--------------------------------------------------------------------------------
/app/model/category.js:
--------------------------------------------------------------------------------
1 | const categoryData = require('../InitData/category')
2 |
3 | module.exports = app => {
4 | const mongoose = app.mongoose
5 |
6 | const categorySchema = new mongoose.Schema({
7 | count: Number,
8 | id: Number,
9 | ids: [],
10 | image_url: String,
11 | level: Number,
12 | name: String,
13 | sub_categories: [{
14 | count: Number,
15 | id: Number,
16 | image_url: String,
17 | level: Number,
18 | name: String
19 | }, ]
20 | });
21 |
22 | categorySchema.statics.addCategory = async function(type) {
23 | const categoryName = type.split('/')
24 |
25 | try {
26 | const allcate = await this.findOne()
27 | const subcate = await this.findOne({
28 | name: categoryName[0]
29 | })
30 | allcate.count++;
31 | subcate.count++;
32 | subcate.sub_categories.map(item => {
33 | if (item.name == categoryName[1]) {
34 | return item.count++
35 | }
36 | })
37 | await allcate.save();
38 | await subcate.save();
39 | console.log('保存cetegroy成功');
40 | return
41 | } catch (err) {
42 | console.log('保存cetegroy失败');
43 | throw new Error(err)
44 | }
45 |
46 | }
47 |
48 | const Category = mongoose.model('Category', categorySchema)
49 |
50 | Category.findOne((err, data) => {
51 | if (!data) {
52 | for (let i = 0; i < categoryData.length; i++) {
53 | Category.create(categoryData[i])
54 | }
55 | }
56 | })
57 |
58 | return Category
59 | }
--------------------------------------------------------------------------------
/app/model/city.js:
--------------------------------------------------------------------------------
1 | const cityData = require('../InitData/cities')
2 |
3 | module.exports = app => {
4 | const mongoose = app.mongoose
5 |
6 | const citySchema = new mongoose.Schema({
7 | data: {}
8 | })
9 |
10 | // 注意这里不能用箭头函数
11 | citySchema.statics.cityGuess = function(name) {
12 | return new Promise(async (resolve, reject) => {
13 | const firtWord = name.substr(0, 1).toUpperCase()
14 | try {
15 | const city = await this.findOne()
16 | Object.entries(city.data).forEach(item => {
17 | if (item[0] == firtWord) {
18 | item[1].forEach(cityItem => {
19 | if (cityItem.pinyin == name) {
20 | resolve(cityItem)
21 | }
22 | })
23 | }
24 | })
25 | } catch (err) {
26 | reject({
27 | name: 'ERROR_DATA',
28 | message: '查找数据失败'
29 | })
30 |
31 | }
32 | })
33 | }
34 |
35 | citySchema.statics.cityHot = function() {
36 | return new Promise(async (resolve, reject) => {
37 | try {
38 | const city = await this.findOne()
39 | resolve(city.data.hotCities)
40 | } catch (err) {
41 | reject({
42 | name: 'ERROR_DATA',
43 | message: '查找数据失败',
44 | })
45 | }
46 | })
47 | }
48 |
49 | citySchema.statics.cityGroup = function() {
50 | return new Promise(async (resolve, reject) => {
51 | try {
52 | const city = await this.findOne()
53 | const cityObj = city.data
54 | delete(cityObj._id)
55 | delete(cityObj.hotCities)
56 | resolve(cityObj)
57 | } catch (err) {
58 | reject({
59 | name: 'ERROR_DATA',
60 | message: '查找数据失败',
61 | });
62 | }
63 | })
64 | }
65 |
66 | citySchema.statics.getCityById = function(id) {
67 | return new Promise(async (resolve, reject) => {
68 | try {
69 | const city = await this.findOne();
70 | Object.entries(city.data).forEach(item => {
71 | if (item[0] !== '_id' && item[0] !== 'hotCities') {
72 | item[1].forEach(cityItem => {
73 | if (cityItem.id == id) {
74 | resolve(cityItem)
75 | }
76 | })
77 | }
78 | })
79 | } catch (err) {
80 | reject({
81 | name: 'ERROR_DATA',
82 | message: '查找数据失败',
83 | });
84 | }
85 | })
86 | }
87 |
88 | const Cities = mongoose.model('City', citySchema)
89 |
90 | Cities.findOne((err, data) => {
91 | if (!data) {
92 | Cities.create({ data: cityData })
93 | }
94 | })
95 |
96 | return Cities
97 | }
--------------------------------------------------------------------------------
/app/model/delivery.js:
--------------------------------------------------------------------------------
1 | const deliveryData = require('../InitData/delivery')
2 |
3 | module.exports = app => {
4 | const mongoose = app.mongoose
5 |
6 | const deliverySchema = new mongoose.Schema({
7 | color: String,
8 | id: Number,
9 | is_solid: Boolean,
10 | text: String
11 | })
12 |
13 | deliverySchema.index({ index: 1 });
14 |
15 | const Delivery = mongoose.model('Delivery', deliverySchema)
16 |
17 | Delivery.findOne((err, data) => {
18 | if (!data) {
19 | Delivery.create(deliveryData);
20 | }
21 | })
22 |
23 | return Delivery
24 | }
--------------------------------------------------------------------------------
/app/model/entry.js:
--------------------------------------------------------------------------------
1 | const entryData = require('../InitData/entry')
2 |
3 | module.exports = app => {
4 | const mongoose = app.mongoose
5 |
6 | const entrySchema = new mongoose.Schema({
7 | id: Number,
8 | is_in_serving: Boolean,
9 | description: String,
10 | title: String,
11 | link: String,
12 | image_url: String,
13 | icon_url: String,
14 | title_color: String
15 | })
16 |
17 | const Entry=mongoose.model('Entry', entrySchema)
18 |
19 | Entry.findOne((err, data) => {
20 | if (!data) {
21 | for (let i = 0; i < entryData.length; i++) {
22 | Entry.create(entryData[i]);
23 | }
24 | }
25 | })
26 |
27 | return Entry
28 | }
--------------------------------------------------------------------------------
/app/model/explain.js:
--------------------------------------------------------------------------------
1 | const explainData = require('../InitData/explain')
2 |
3 | module.exports = app => {
4 | const mongoose = app.mongoose
5 | const Schema = mongoose.Schema;
6 |
7 | const explainSchema = new Schema({
8 | data: Schema.Types.Mixed,
9 | })
10 |
11 | const Explain = mongoose.model('Explain', explainSchema);
12 |
13 | Explain.findOne((err, data) => {
14 | if (!data) {
15 | Explain.create({ data: explainData });
16 | }
17 | })
18 |
19 | return Explain
20 | }
--------------------------------------------------------------------------------
/app/model/food.js:
--------------------------------------------------------------------------------
1 | module.exports = app => {
2 | const mongoose = app.mongoose
3 | const Schema = mongoose.Schema;
4 |
5 | const foodSchema = new mongoose.Schema({
6 | rating: { type: Number, default: 0 },
7 | is_featured: { type: Number, default: 0 },
8 | restaurant_id: { type: Number, isRequired: true },
9 | category_id: { type: Number, isRequired: true },
10 | pinyin_name: { type: String, default: '' },
11 | display_times: { type: Array, default: [] },
12 | attrs: { type: Array, default: [] },
13 | description: { type: String, default: "" },
14 | month_sales: { type: Number, default: 0 },
15 | rating_count: { type: Number, default: 0 },
16 | tips: String,
17 | image_path: String,
18 | specifications: [Schema.Types.Mixed],
19 | server_utc: { type: Date, default: Date.now() },
20 | is_essential: { type: Boolean, default: false },
21 | attributes: { type: Array, default: [] },
22 | item_id: { type: Number, isRequired: true },
23 | limitation: Schema.Types.Mixed,
24 | name: { type: String, isRequired: true },
25 | satisfy_count: { type: Number, default: 0 },
26 | activity: Schema.Types.Mixed,
27 | satisfy_rate: { type: Number, default: 0 },
28 | specfoods: [{
29 | original_price: { type: Number, default: 0 },
30 | sku_id: { type: Number, isRequired: true },
31 | name: { type: String, isRequired: true },
32 | pinyin_name: { type: String, default: "" },
33 | restaurant_id: { type: Number, isRequired: true },
34 | food_id: { type: Number, isRequired: true },
35 | packing_fee: { type: Number, default: 0 },
36 | recent_rating: { type: Number, default: 0 },
37 | promotion_stock: { type: Number, default: -1 },
38 | price: { type: Number, default: 0 },
39 | sold_out: { type: Boolean, default: false },
40 | recent_popularity: { type: Number, default: 0 },
41 | is_essential: { type: Boolean, default: false },
42 | item_id: { type: Number, isRequired: true },
43 | checkout_mode: { type: Number, default: 1 },
44 | stock: { type: Number, default: 1000 },
45 | specs_name: String,
46 | specs: [{
47 | name: String,
48 | value: String
49 | }]
50 | }]
51 | })
52 |
53 | // const menuSchema = new mongoose.Schema({
54 | // description: String,
55 | // is_selected: { type: Boolean, default: true },
56 | // icon_url: { type: String, default: '' },
57 | // name: { type: String, isRequired: true },
58 | // id: { type: Number, isRequired: true },
59 | // restaurant_id: { type: Number, isRequired: true },
60 | // type: { type: Number, default: 1 },
61 | // foods: [foodSchema]
62 | // })
63 |
64 | foodSchema.index({ id: 1 })
65 | // menuSchema.index({ id: 1 })
66 |
67 | const Food = mongoose.model('Food', foodSchema)
68 | // const Menu = mongoose.model('Menu', menuSchema)
69 |
70 | // return { Food, Menu }
71 | return Food
72 | }
--------------------------------------------------------------------------------
/app/model/hongbao.js:
--------------------------------------------------------------------------------
1 | const hongbaoData = require('../InitData/hongbao')
2 |
3 | module.exports = app => {
4 | const mongoose = app.mongoose
5 |
6 | const hongbaoSchema = new mongoose.Schema({
7 | id: Number,
8 | sn: String,
9 | user_id: Number,
10 | amount: Number,
11 | sum_condition: Number,
12 | name: String,
13 | phone: String,
14 | begin_date: String,
15 | end_date: String,
16 | description_map: {
17 | phone: String,
18 | online_paid_only: String,
19 | validity_delta: String,
20 | validity_periods: String,
21 | sum_condition: String
22 | },
23 | limit_map: {},
24 | status: Number,
25 | present_status: Number,
26 | share_status: Number,
27 | })
28 |
29 | hongbaoSchema.index({ id: 1 });
30 |
31 | const Hongbao = mongoose.model('Hongbao', hongbaoSchema);
32 |
33 | Hongbao.findOne((err, data) => {
34 | if (!data) {
35 | hongbaoData.forEach(item => {
36 | Hongbao.create(item)
37 | })
38 | }
39 | })
40 |
41 | return Hongbao
42 | }
--------------------------------------------------------------------------------
/app/model/ids.js:
--------------------------------------------------------------------------------
1 | module.exports = app => {
2 | const mongoose = app.mongoose
3 | const idsSchema = new mongoose.Schema({
4 | restaurant_id: Number,
5 | food_id: Number,
6 | order_id: Number,
7 | user_id: Number,
8 | address_id: Number,
9 | cart_id: Number,
10 | img_id: Number,
11 | category_id: Number,
12 | item_id: Number,
13 | sku_id: Number,
14 | admin_id: Number,
15 | statis_id: Number,
16 | });
17 |
18 | const Ids = mongoose.model('Ids', idsSchema)
19 |
20 | Ids.findOne((err, data) => {
21 | if (!data) {
22 | const newIds = new Ids({
23 | restaurant_id: 0,
24 | food_id: 0,
25 | order_id: 0,
26 | user_id: 0,
27 | address_id: 0,
28 | cart_id: 0,
29 | img_id: 0,
30 | category_id: 0,
31 | item_id: 0,
32 | sku_id: 0,
33 | admin_id: 0,
34 | statis_id: 0,
35 | });
36 | newIds.save();
37 | }
38 | })
39 |
40 | return Ids
41 | }
--------------------------------------------------------------------------------
/app/model/menu.js:
--------------------------------------------------------------------------------
1 | module.exports = app => {
2 | const mongoose = app.mongoose
3 | const Schema = mongoose.Schema;
4 |
5 | const foodSchema = new mongoose.Schema({
6 | rating: { type: Number, default: 0 },
7 | is_featured: { type: Number, default: 0 },
8 | restaurant_id: { type: Number, isRequired: true },
9 | category_id: { type: Number, isRequired: true },
10 | pinyin_name: { type: String, default: '' },
11 | display_times: { type: Array, default: [] },
12 | attrs: { type: Array, default: [] },
13 | description: { type: String, default: "" },
14 | month_sales: { type: Number, default: 0 },
15 | rating_count: { type: Number, default: 0 },
16 | tips: String,
17 | image_path: String,
18 | specifications: [Schema.Types.Mixed],
19 | server_utc: { type: Date, default: Date.now() },
20 | is_essential: { type: Boolean, default: false },
21 | attributes: { type: Array, default: [] },
22 | item_id: { type: Number, isRequired: true },
23 | limitation: Schema.Types.Mixed,
24 | name: { type: String, isRequired: true },
25 | satisfy_count: { type: Number, default: 0 },
26 | activity: Schema.Types.Mixed,
27 | satisfy_rate: { type: Number, default: 0 },
28 | specfoods: [{
29 | original_price: { type: Number, default: 0 },
30 | sku_id: { type: Number, isRequired: true },
31 | name: { type: String, isRequired: true },
32 | pinyin_name: { type: String, default: "" },
33 | restaurant_id: { type: Number, isRequired: true },
34 | food_id: { type: Number, isRequired: true },
35 | packing_fee: { type: Number, default: 0 },
36 | recent_rating: { type: Number, default: 0 },
37 | promotion_stock: { type: Number, default: -1 },
38 | price: { type: Number, default: 0 },
39 | sold_out: { type: Boolean, default: false },
40 | recent_popularity: { type: Number, default: 0 },
41 | is_essential: { type: Boolean, default: false },
42 | item_id: { type: Number, isRequired: true },
43 | checkout_mode: { type: Number, default: 1 },
44 | stock: { type: Number, default: 1000 },
45 | specs_name: String,
46 | specs: [{
47 | name: String,
48 | value: String
49 | }]
50 | }]
51 | })
52 |
53 | const menuSchema = new mongoose.Schema({
54 | description: String,
55 | is_selected: { type: Boolean, default: true },
56 | icon_url: { type: String, default: '' },
57 | name: { type: String, isRequired: true },
58 | id: { type: Number, isRequired: true },
59 | restaurant_id: { type: Number, isRequired: true },
60 | type: { type: Number, default: 1 },
61 | foods: [foodSchema]
62 | })
63 |
64 | // foodSchema.index({ id: 1 })
65 | menuSchema.index({ id: 1 })
66 |
67 | // const Food = mongoose.model('Food', foodSchema)
68 | const Menu = mongoose.model('Menu', menuSchema)
69 |
70 | // return { Food, Menu }
71 | return Menu
72 | }
--------------------------------------------------------------------------------
/app/model/order.js:
--------------------------------------------------------------------------------
1 | module.exports = app => {
2 | const mongoose = app.mongoose
3 |
4 | const orderSchema = new mongoose.Schema({
5 | basket: {
6 | abandoned_extra: [{
7 | category_id: Number,
8 | name: { type: String, default: '' },
9 | price: { type: Number, default: 0 },
10 | quantity: { type: Number, default: 0 },
11 | }],
12 | deliver_fee: {
13 | category_id: { type: Number, default: 2 },
14 | name: { type: String, default: '配送费' },
15 | price: { type: Number, default: 4 },
16 | quantity: { type: Number, default: 1 },
17 | },
18 | extra: [],
19 | group: [
20 | [{
21 | attrs: [],
22 | new_specs: [],
23 | name: String,
24 | price: Number,
25 | quantity: Number,
26 | specs: [String]
27 | }]
28 | ],
29 | packing_fee: {
30 | category_id: { type: Number, default: 1 },
31 | name: { type: String, default: '餐盒' },
32 | price: Number,
33 | quantity: Number
34 | },
35 | pindan_map: []
36 | },
37 | formatted_created_at: String,
38 | order_time: Number,
39 | time_pass: Number,
40 | id: Number,
41 | is_brand: { type: Number, default: 0 },
42 | is_deletable: { type: Number, default: 1 },
43 | is_new_pay: { type: Number, default: 1 },
44 | is_pindan: { type: Number, default: 0 },
45 | operation_confirm: { type: Number, default: 0 },
46 | operation_pay: { type: Number, default: 0 },
47 | operation_rate: { type: Number, default: 0 },
48 | operation_rebuy: { type: Number, default: 2 },
49 | operation_upload_photo: { type: Number, default: 0 },
50 | pay_remain_seconds: { type: Number, default: 0 },
51 | rated_point: { type: Number, default: 0 },
52 | remind_reply_count: { type: Number, default: 0 },
53 | restaurant_id: Number,
54 | restaurant_image_hash: String,
55 | restaurant_image_url: String,
56 | restaurant_name: String,
57 | restaurant_type: { type: Number, default: 0 },
58 | status_bar: {
59 | color: String,
60 | image_type: String,
61 | sub_title: String,
62 | title: String,
63 | },
64 | status_code: { type: Number, default: 0 },
65 | timeline_node: {
66 | actions: [],
67 | description: String,
68 | in_processing: { type: Number, default: 0 },
69 | sub_description: String,
70 | title: String,
71 | },
72 | top_show: { type: Number, default: 0 },
73 | total_amount: Number,
74 | total_quantity: Number,
75 | unique_id: Number,
76 | user_id: Number,
77 | address_id: Number,
78 | })
79 |
80 | orderSchema.index({ id: 1 });
81 |
82 | return mongoose.model('Order', orderSchema);
83 | }
--------------------------------------------------------------------------------
/app/model/payments.js:
--------------------------------------------------------------------------------
1 | const paymentsData = require('../InitData/payments')
2 |
3 | module.exports = app => {
4 | const mongoose = app.mongoose
5 |
6 | const paymentsSchema = new mongoose.Schema({
7 | description: String,
8 | disabled_reason: String,
9 | id: Number,
10 | is_online_payment: Boolean,
11 | name: String,
12 | promotion: [],
13 | select_state: Number,
14 | })
15 |
16 | const Payments = mongoose.model('Payments', paymentsSchema);
17 |
18 | Payments.findOne((err, data) => {
19 | if (!data) {
20 | paymentsData.forEach(item => {
21 | Payments.create(item);
22 | })
23 | }
24 | })
25 |
26 | return Payments
27 | }
--------------------------------------------------------------------------------
/app/model/rating.js:
--------------------------------------------------------------------------------
1 | const ratingData = require('../InitData/rate')
2 |
3 | module.exports = app => {
4 | const mongoose = app.mongoose
5 |
6 | const ratingSchema = new mongoose.Schema({
7 | restaurant_id: Number,
8 | ratings: [{
9 | avatar: { type: String, default: '' },
10 | highlights: [],
11 | item_ratings: [{
12 | food_id: Number,
13 | food_name: String,
14 | image_hash: { type: String, default: '' },
15 | is_valid: { type: Number, default: 1 },
16 | }, ],
17 | rated_at: String,
18 | rating_star: Number,
19 | rating_text: String,
20 | tags: { type: Array, default: [] },
21 | time_spent_desc: String,
22 | username: { type: String, default: "匿名用户" },
23 | }, ],
24 | scores: {
25 | compare_rating: { type: Number, default: 0 },
26 | deliver_time: { type: Number, default: 0 },
27 | food_score: { type: Number, default: 0 },
28 | order_rating_amount: { type: Number, default: 0 },
29 | overall_score: { type: Number, default: 0 },
30 | service_score: { type: Number, default: 0 },
31 | },
32 | tags: [{
33 | count: { type: Number, default: 0 },
34 | name: String,
35 | unsatisfied: { type: Boolean, default: false },
36 | }]
37 | })
38 |
39 | ratingSchema.index({ restaurant_id: 1 });
40 |
41 | ratingSchema.statics.initData = async function(restaurant_id) {
42 | try {
43 | const data = await this.findOne({ restaurant_id })
44 | if (!data) {
45 | const newRating = {
46 | restaurant_id,
47 | ratings: ratingData.ratingList,
48 | scores: ratingData.scores,
49 | tags: ratingData.tags
50 | }
51 | console.log('[newRating]',newRating)
52 | await this.create(newRating)
53 | return true
54 | } else {
55 | return false
56 | }
57 | } catch (err) {
58 | console.log('初始化评论数据失败');
59 | throw new Error(err)
60 | }
61 | }
62 |
63 | ratingSchema.statics.getData = async function(restaurant_id, type) {
64 | try {
65 | const data = await this.findOne({ restaurant_id }, '-_id');
66 |
67 | if (!data) {
68 | throw new Error('未找到当前餐馆的评论数据');
69 | } else {
70 | return data[type]
71 | }
72 | } catch (err) {
73 | console.log('初始化评论数据失败');
74 | throw new Error(err)
75 | }
76 | }
77 |
78 |
79 | return mongoose.model('Rating', ratingSchema)
80 | }
--------------------------------------------------------------------------------
/app/model/remark.js:
--------------------------------------------------------------------------------
1 | const remarkData = require('../InitData/remark')
2 |
3 | module.exports = app => {
4 | const mongoose = app.mongoose
5 |
6 | const remarkSchema = new mongoose.Schema({
7 | remarks: [],
8 | })
9 |
10 | const Remark = mongoose.model('Remark', remarkSchema);
11 |
12 | Remark.findOne((err, data) => {
13 | if (!data) {
14 | Remark.create(remarkData);
15 | }
16 | })
17 |
18 | return Remark
19 | }
--------------------------------------------------------------------------------
/app/model/shop.js:
--------------------------------------------------------------------------------
1 | module.exports = app => {
2 | const mongoose = app.mongoose
3 |
4 | const shopSchema = new mongoose.Schema({
5 | activities: [{
6 | description: String,
7 | icon_color: String,
8 | icon_name: String,
9 | id: Number,
10 | name: String,
11 | }],
12 | address: String,
13 | delivery_mode: {
14 | color: String,
15 | id: Number,
16 | is_solid: Boolean,
17 | text: String
18 | },
19 | description: { type: String, default: "" },
20 | order_lead_time: { type: String, default: "" },
21 | distance: { type: String, default: "" },
22 | location: { type: [Number], index: '2d' },
23 | float_delivery_fee: { type: Number, default: 0 },
24 | float_minimum_order_amount: { type: Number, default: 0 },
25 | id: Number,
26 | category: String,
27 | identification: {
28 | company_name: { type: String, default: "" },
29 | identificate_agency: { type: String, default: "" },
30 | identificate_date: { type: Date, default: Date.now },
31 | legal_person: { type: String, default: "" },
32 | licenses_date: { type: String, default: "" },
33 | licenses_number: { type: String, default: "" },
34 | licenses_scope: { type: String, default: "" },
35 | operation_period: { type: String, default: "" },
36 | registered_address: { type: String, default: "" },
37 | registered_number: { type: String, default: "" },
38 | },
39 | image_path: { type: String, default: "" },
40 | is_premium: { type: Boolean, default: false },
41 | is_new: { type: Boolean, default: false },
42 | latitude: Number,
43 | longitude: Number,
44 | license: {
45 | business_license_image: { type: String, default: "" },
46 | catering_service_license_image: { type: String, default: "" },
47 | },
48 | name: {
49 | type: String,
50 | required: true
51 | },
52 | opening_hours: { type: Array, default: ["08:30/20:30"] },
53 | phone: {
54 | type: String,
55 | required: true
56 | },
57 | piecewise_agent_fee: {
58 | tips: String
59 | },
60 | promotion_info: { type: String, default: "欢迎光临,用餐高峰请提前下单,谢谢" },
61 | rating: { type: Number, default: 0 },
62 | rating_count: { type: Number, default: 0 },
63 | recent_order_num: { type: Number, default: 0 },
64 | status: { type: Number, default: 0 },
65 | supports: [{
66 | description: String,
67 | icon_color: String,
68 | icon_name: String,
69 | id: Number,
70 | name: String
71 | }],
72 | })
73 |
74 | shopSchema.index({ id: 1 })
75 |
76 | return mongoose.model('Shop', shopSchema)
77 | }
--------------------------------------------------------------------------------
/app/model/user.js:
--------------------------------------------------------------------------------
1 | module.exports = app => {
2 | const mongoose = app.mongoose
3 |
4 | const userSchema = new mongoose.Schema({
5 | user_id: Number,
6 | username: String,
7 | password: String,
8 | })
9 |
10 |
11 | return mongoose.model('User', userSchema)
12 | }
--------------------------------------------------------------------------------
/app/model/userInfo.js:
--------------------------------------------------------------------------------
1 | module.exports = app => {
2 | const mongoose = app.mongoose
3 |
4 | const userInfoSchema = new mongoose.Schema({
5 | avatar: { type: String, default: 'default.jpg' },
6 | balance: { type: Number, default: 0 },
7 | brand_member_new: { type: Number, default: 0 },
8 | current_address_id: { type: Number, default: 0 },
9 | current_invoice_id: { type: Number, default: 0 },
10 | delivery_card_expire_days: { type: Number, default: 0 },
11 | email: { type: String, default: '' },
12 | gift_amount: { type: Number, default: 3 },
13 | city: String,
14 | registe_time: String,
15 | id: Number,
16 | user_id: Number,
17 | is_active: { type: Number, default: 1 },
18 | is_email_valid: { type: Boolean, default: false },
19 | is_mobile_valid: { type: Boolean, default: true },
20 | mobile: { type: String, default: '' },
21 | point: { type: Number, default: 0 },
22 | username: String,
23 | column_desc: {
24 | game_desc: { type: String, default: '玩游戏领红包' },
25 | game_image_hash: { type: String, default: '05f108ca4e0c543488799f0c7c708cb1jpeg' },
26 | game_is_show: { type: Number, default: 1 },
27 | game_link: { type: String, default: 'https://gamecenter.faas.ele.me' },
28 | gift_mall_desc: { type: String, default: '0元好物在这里' },
29 | },
30 | })
31 |
32 | userInfoSchema.index({ id: 1 });
33 |
34 | return mongoose.model('UserInfo', userInfoSchema)
35 | }
--------------------------------------------------------------------------------
/app/public/temp/1669ffd40d130.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/1669ffd40d130.png
--------------------------------------------------------------------------------
/app/public/temp/1669ffd4f6032.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/1669ffd4f6032.png
--------------------------------------------------------------------------------
/app/public/temp/1669ffd5b9931.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/1669ffd5b9931.png
--------------------------------------------------------------------------------
/app/public/temp/166a00081cc33.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166a00081cc33.png
--------------------------------------------------------------------------------
/app/public/temp/166a000a3ac34.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166a000a3ac34.png
--------------------------------------------------------------------------------
/app/public/temp/166a445d19535.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166a445d19535.png
--------------------------------------------------------------------------------
/app/public/temp/166a445d88e36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166a445d88e36.png
--------------------------------------------------------------------------------
/app/public/temp/166a44605bf37.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166a44605bf37.png
--------------------------------------------------------------------------------
/app/public/temp/166a4cb194a39.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166a4cb194a39.png
--------------------------------------------------------------------------------
/app/public/temp/166a4cb227438.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166a4cb227438.png
--------------------------------------------------------------------------------
/app/public/temp/166a4cb3bb440.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166a4cb3bb440.png
--------------------------------------------------------------------------------
/app/public/temp/166a5042e7741.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166a5042e7741.png
--------------------------------------------------------------------------------
/app/public/temp/166a504b61d42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166a504b61d42.png
--------------------------------------------------------------------------------
/app/public/temp/166a50b095d43.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166a50b095d43.png
--------------------------------------------------------------------------------
/app/public/temp/166a50c79ec44.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166a50c79ec44.png
--------------------------------------------------------------------------------
/app/public/temp/166a50cc1fd45.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166a50cc1fd45.png
--------------------------------------------------------------------------------
/app/public/temp/166be97f19f46.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166be97f19f46.png
--------------------------------------------------------------------------------
/app/public/temp/166be9819c848.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166be9819c848.png
--------------------------------------------------------------------------------
/app/public/temp/166be98217b47.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166be98217b47.png
--------------------------------------------------------------------------------
/app/public/temp/166c297677250.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166c297677250.png
--------------------------------------------------------------------------------
/app/public/temp/166c29773c749.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166c29773c749.png
--------------------------------------------------------------------------------
/app/public/temp/166c297869051.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166c297869051.png
--------------------------------------------------------------------------------
/app/public/temp/166c29800f252.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166c29800f252.png
--------------------------------------------------------------------------------
/app/public/temp/166c3322a8553.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166c3322a8553.png
--------------------------------------------------------------------------------
/app/public/temp/166c3a453fa54.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166c3a453fa54.png
--------------------------------------------------------------------------------
/app/public/temp/166c414dffa55.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166c414dffa55.png
--------------------------------------------------------------------------------
/app/public/temp/166c807a60856.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166c807a60856.png
--------------------------------------------------------------------------------
/app/public/temp/166c810c34d57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166c810c34d57.png
--------------------------------------------------------------------------------
/app/public/temp/166cd80824658.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166cd80824658.png
--------------------------------------------------------------------------------
/app/public/temp/166e7b704e959.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166e7b704e959.png
--------------------------------------------------------------------------------
/app/public/temp/166e7c285a760.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166e7c285a760.png
--------------------------------------------------------------------------------
/app/public/temp/166e7c303c461.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166e7c303c461.png
--------------------------------------------------------------------------------
/app/public/temp/166e7c3bbb262.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166e7c3bbb262.png
--------------------------------------------------------------------------------
/app/public/temp/166e7c3eed963.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166e7c3eed963.png
--------------------------------------------------------------------------------
/app/public/temp/166e827ad7164.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166e827ad7164.png
--------------------------------------------------------------------------------
/app/public/temp/166e82820b265.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166e82820b265.png
--------------------------------------------------------------------------------
/app/public/temp/166f24683de66.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166f24683de66.png
--------------------------------------------------------------------------------
/app/public/temp/166f246de0767.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/166f246de0767.png
--------------------------------------------------------------------------------
/app/public/temp/16705c7696668.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/16705c7696668.png
--------------------------------------------------------------------------------
/app/public/temp/16705c7a8a769.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/16705c7a8a769.png
--------------------------------------------------------------------------------
/app/public/temp/1670fdf83cd70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/1670fdf83cd70.png
--------------------------------------------------------------------------------
/app/public/temp/1670fdfa39371.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/1670fdfa39371.png
--------------------------------------------------------------------------------
/app/public/temp/1670fdfd42072.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majun00/egg-api/60a2865bf7e89237eb09f1aabc0c8bbd8f78692c/app/public/temp/1670fdfd42072.jpg
--------------------------------------------------------------------------------
/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @param {Egg.Application} app - egg application
5 | */
6 | module.exports = app => {
7 | const { router, controller, middlewares } = app
8 | const checkApiToken = middlewares.checkAdmin()
9 |
10 | router.post('/admin/login', controller.admin.admin.login)
11 | router.get('/admin/info', controller.admin.admin.getAdminInfo)
12 | router.get('/admin/signout', controller.admin.admin.signout)
13 | router.get('/admin/all', controller.admin.admin.getAllAdmin)
14 | router.get('/admin/count', controller.admin.admin.getAdminCount)
15 | router.post('/admin/update/avatar/:admin_id', controller.admin.admin.updateAvatar);
16 |
17 | router.post('/member/v1/users/:user_id/delivery_card/physical_card/bind', controller.member.vipCart.useCart)
18 |
19 | router.get('/promotion/v2/users/:user_id/hongbaos', controller.promotion.hongbao.getHongbao)
20 | router.get('/promotion/v2/users/:user_id/expired_hongbaos', controller.promotion.hongbao.getExpiredHongbao)
21 | router.post('/v1/users/:user_id/hongbao/exchange', controller.promotion.hongbao.exchange);
22 |
23 | router.get('/shopping/v1/restaurants/delivery_modes', controller.shopping.category.getDelivery);
24 | router.get('/shopping/v1/restaurants/activity_attributes', controller.shopping.category.getActivity);
25 | router.get('/shopping/v2/restaurant/category', controller.shopping.category.getCategories)
26 |
27 | router.post('/shopping/addfood', checkApiToken, controller.shopping.food.addFood);
28 | router.get('/shopping/v2/foods', controller.shopping.food.getFoods);
29 | router.get('/shopping/v2/foods/count', controller.shopping.food.getFoodsCount);
30 | router.delete('/shopping/v2/food/:food_id', controller.shopping.food.deleteFood);
31 | router.post('/shopping/v2/updatefood', checkApiToken, controller.shopping.food.updateFood);
32 | router.get('/shopping/getcategory/:restaurant_id', controller.shopping.food.getCategory)
33 | router.post('/shopping/addcategory', checkApiToken, controller.shopping.food.addCategory);
34 | router.get('/shopping/v2/menu/:category_id', controller.shopping.food.getMenuDetail)
35 | router.get('/shopping/v2/menu', controller.shopping.food.getMenu)
36 |
37 | router.post('/shopping/addShop', checkApiToken, controller.shopping.shop.addShop)
38 | router.get('/shopping/restaurants/count', controller.shopping.shop.getShopCount)
39 | router.get('/shopping/restaurants', controller.shopping.shop.getRestaurants)
40 | router.post('/shopping/updateshop', checkApiToken, controller.shopping.shop.updateshop)
41 | router.delete('/shopping/restaurant/:restaurant_id', controller.shopping.shop.deleteResturant)
42 | router.get('/shopping/restaurant/:restaurant_id', controller.shopping.shop.getRestaurantDetail);
43 | router.get('/v4/restaurants', controller.shopping.shop.searchResaturant);
44 |
45 | router.get('/statis/admin/:date/count', controller.statis.statis.adminCount)
46 | router.get('/statis/user/:date/count', controller.statis.statis.userCount)
47 | router.get('/statis/order/:date/count', controller.statis.statis.orderCount)
48 |
49 | router.get('/ugc/v2/restaurants/:restaurant_id/ratings', controller.ugc.rating.getRatings);
50 | router.get('/ugc/v2/restaurants/:restaurant_id/ratings/scores', controller.ugc.rating.getScores);
51 | router.get('/ugc/v2/restaurants/:restaurant_id/ratings/tags', controller.ugc.rating.getTags);
52 |
53 | router.get('/v1/users/:user_id/addresses', controller.v1.addre.getAddress);
54 | router.post('/v1/users/:user_id/addresses', controller.v1.addre.addAddress);
55 | router.delete('/v1/users/:user_id/addresses/:address_id', controller.v1.addre.deleteAddress);
56 | router.get('/v1/addresse/:address_id', controller.v1.addre.getAddAddressById);
57 |
58 | router.post('/v1/captchas', controller.v1.captchas.getCaptchas);
59 | router.post('/v1/carts/checkout', controller.v1.carts.checkout);
60 |
61 | router.get('/v1/cities', controller.v1.city.getCity)
62 | router.get('/v1/cities/:id', controller.v1.city.getCityById)
63 | router.get('/v2/pois/:geohash', controller.v1.city.pois);
64 |
65 | router.post('/v1/users/:user_id/carts/:cart_id/orders', controller.v1.order.postOrder);
66 | router.get('/bos/v2/users/:user_id/orders', controller.v1.order.getOrders)
67 | router.get('/bos/v1/users/:user_id/orders/:order_id/snapshot', controller.v1.order.getDetail)
68 | router.get('/bos/orders', controller.v1.order.getAllOrders)
69 | router.get('/bos/orders/count', controller.v1.order.getOrdersCount)
70 |
71 | router.get('/v1/carts/:cart_id/remarks', controller.v1.remark.getRemarks);
72 | router.get('/v1/pois', controller.v1.search.search)
73 |
74 | router.get('/v2/index_entry', controller.v2.entry.getEntry);
75 |
76 | router.get('/v1/users/list', controller.v2.user.getUserList);
77 | router.get('/v1/users/count', controller.v2.user.getUserCount);
78 | router.get('/v1/user/:user_id', controller.v2.user.getInfoById);
79 | router.get('/v1/user/city/count', controller.v2.user.getUserCity);
80 | router.get('/v2/signout', controller.v2.user.signout);
81 | router.post('/v2/login', controller.v2.user.login);
82 | router.get('/v1/user', controller.v2.user.getInfo);
83 |
84 | router.get('/v3/profile/explain', controller.v3.explain.getExpalin)
85 |
86 | router.post('/v1/addimg/:type', controller.upload.upload);
87 |
88 | // router.resources('teachers', '/v1/teachers', checkApiToken, controller.teachers)
89 | // router.resources('auth', '/v1/auth', controller.auth)
90 | // router.delete('/v1/auth', controller.auth.destroy)
91 | // router.resources('course_categories', '/v1/course_categories', checkApiToken, controller.categories)
92 | }
--------------------------------------------------------------------------------
/app/service/address.js:
--------------------------------------------------------------------------------
1 | const Service = require('egg').Service;
2 | const tencentkey = 'RLHBZ-WMPRP-Q3JDS-V2IQA-JNRFH-EJBHL';
3 | const tencentkey2 = 'RRXBZ-WC6KF-ZQSJT-N2QU7-T5QIT-6KF5X';
4 | const tencentkey3 = 'OHTBZ-7IFRG-JG2QF-IHFUK-XTTK6-VXFBN';
5 | const baidukey = 'fjke3YUipM9N64GdOIh1DNeK2APO2WcT';
6 | const baidukey2 = 'fjke3YUipM9N64GdOIh1DNeK2APO2WcT';
7 |
8 | class AddressService extends Service {
9 | // 获取定位地址
10 | async guessPosition() {
11 | const ctx = this.ctx
12 | return new Promise(async (resolve, reject) => {
13 | // let ip = ctx.request.headers['x-forwarded-for'] ||
14 | // ctx.request.connection.remoteAddress ||
15 | // ctx.request.socket.remoteAddress ||
16 | // ctx.request.connection.socket.remoteAddress;
17 | // const ipArr = ip.split(':');
18 | // ip = ipArr[ipArr.length - 1];
19 | // if (process.env.NODE_ENV == 'development') {
20 | // ip = '180.158.102.141';
21 | // }
22 | let ip = '180.158.102.141';
23 | try {
24 | let result = (await ctx.curl('http://apis.map.qq.com/ws/location/v1/ip', {
25 | data: {
26 | ip,
27 | key: tencentkey,
28 | },
29 | dataType: 'json',
30 | })).data
31 |
32 | if (result.status != 0) {
33 | result = (await ctx.curl('http://apis.map.qq.com/ws/location/v1/ip', {
34 | data: {
35 | ip,
36 | key: tencentkey2,
37 | }
38 | })).data
39 | }
40 |
41 | if (result.status != 0) {
42 | result = (await ctx.curl('http://apis.map.qq.com/ws/location/v1/ip', {
43 | data: {
44 | ip,
45 | key: tencentkey3,
46 | }
47 | })).data
48 | }
49 |
50 | if (result.status == 0) {
51 | const cityInfo = {
52 | lat: result.result.location.lat,
53 | lng: result.result.location.lng,
54 | city: result.result.ad_info.city,
55 | }
56 | cityInfo.city = cityInfo.city.replace(/市$/, '')
57 | resolve(cityInfo)
58 | } else {
59 | reject('定位失败')
60 | }
61 |
62 | } catch (err) {
63 | reject(err)
64 | }
65 |
66 | })
67 | }
68 |
69 | // 搜索地址
70 | async searchPlace(keyword, cityName, type = 'search') {
71 | const ctx = this.ctx
72 | try {
73 | const resObj = (await ctx.curl('http://apis.map.qq.com/ws/place/v1/search', {
74 | data: {
75 | key: tencentkey,
76 | keyword: encodeURIComponent(keyword),
77 | boundary: 'region(' + encodeURIComponent(cityName) + ',0)',
78 | page_size: 10,
79 | },
80 | dataType: 'json',
81 | })).data
82 | if (resObj.status == 0) {
83 | return resObj
84 | } else {
85 | throw new Error('搜索位置信息失败')
86 | }
87 | } catch (err) {
88 | throw new Error(err);
89 | }
90 | }
91 |
92 | // 测量距离
93 | async getDistance(from, to, type) {
94 | const ctx = this.ctx
95 | try {
96 | let res
97 | res = (await ctx.curl('http://api.map.baidu.com/routematrix/v2/driving', {
98 | data: {
99 | ak: baidukey,
100 | output: 'json',
101 | origins: from,
102 | destinations: to,
103 | },
104 | dataType: 'json',
105 | })).data
106 |
107 | if (res.status !== 0) {
108 | res = (await ctx.curl('http://api.map.baidu.com/routematrix/v2/driving', {
109 | data: {
110 | ak: baidukey2,
111 | output: 'json',
112 | origins: from,
113 | destinations: to,
114 | },
115 | dataType: 'json',
116 | })).data
117 | }
118 |
119 | if (res.status == 0) {
120 | const positionArr = [];
121 | let timevalue;
122 | res.result.forEach(item => {
123 | timevalue = parseInt(item.duration.value) + 1200;
124 | let durationtime = Math.ceil(timevalue % 3600 / 60) + '分钟';
125 | if (Math.floor(timevalue / 3600)) {
126 | durationtime = Math.floor(timevalue / 3600) + '小时' + durationtime;
127 | }
128 | positionArr.push({
129 | distance: item.distance.text,
130 | order_lead_time: durationtime,
131 | })
132 | })
133 | if (type == 'tiemvalue') {
134 | return timevalue
135 | } else {
136 | return positionArr
137 | }
138 | } else {
139 | // console.log('[res]', JSON.stringify(res))
140 | throw new Error('调用百度地图测距失败');
141 | }
142 | } catch (err) {
143 | // console.log('获取位置距离失败')
144 | throw new Error(err);
145 | }
146 |
147 | }
148 |
149 | // 通过ip地址获取精确位置
150 | async geocoder() {
151 |
152 | }
153 |
154 | // 通过geohash获取精确位置
155 | async getpois(lat, lng) {
156 | const ctx = this.ctx
157 | try {
158 | const res = (await ctx.curl('http://apis.map.qq.com/ws/geocoder/v1/', {
159 | data: {
160 | key: tencentkey,
161 | location: lat + ',' + lng
162 | },
163 | dataType: 'json'
164 | })).data
165 | if (res.status == 0) {
166 | return res
167 | } else {
168 | throw new Error('通过获geohash取具体位置失败');
169 | }
170 | } catch (err) {
171 | console.log('getpois获取定位失败')
172 | throw new Error(err);
173 | }
174 | }
175 | }
176 |
177 | module.exports = AddressService;
--------------------------------------------------------------------------------
/app/service/admin/admin.js:
--------------------------------------------------------------------------------
1 | const Service = require('egg').Service
2 | const md5 = require('blueimp-md5')
3 | const dtime = require('moment')
4 | // const jwt = require('jwt-simple')
5 | // const moment = require('moment')
6 |
7 | class AdminService extends Service {
8 | // POST /admin/login
9 | async login() {
10 | const ctx = this.ctx
11 | const { username, password, status = 1 } = ctx.request.body
12 | let message = '注册成功'
13 |
14 | // try {
15 | // if (!user_name) {
16 | // throw new Error('用户名参数错误')
17 | // } else if (!password) {
18 | // throw new Error('密码参数错误')
19 | // }
20 | // } catch (err) {
21 | // console.log(err.message, err);
22 | // ctx.body={
23 | // status: 0,
24 | // type: 'GET_ERROR_PARAM',
25 | // message: err.message,
26 | // }
27 | // return
28 | // }
29 |
30 | // 数据校验
31 | ctx.validate({
32 | username: 'string',
33 | password: 'string'
34 | })
35 |
36 | // 把密码处理成 md5 加密
37 | let pwd = md5(md5(password))
38 |
39 | let user = await ctx.model.Admin.findOne({
40 | username
41 | })
42 |
43 | if (!user) {
44 | const admin_id = await ctx.helper.getId('admin_id')
45 | const adminTip = status == 1 ? '管理员' : ' 超级管理员'
46 | const cityInfo = await ctx.service.address.guessPosition()
47 | const newAdmin = {
48 | id: admin_id,
49 | create_time: dtime().format('YYYY-MM-DD HH:mm'),
50 | city: cityInfo.city,
51 | admin: adminTip,
52 | status,
53 | }
54 |
55 | ctx.request.body.password = pwd
56 | Object.assign(newAdmin, ctx.request.body)
57 | user = await ctx.model.Admin.create(newAdmin)
58 | } else {
59 | if (pwd.toString() !== user.password.toString()) {
60 | ctx.status = 401
61 | return ctx.body = {
62 | status: 0,
63 | type: 'ERROR_PASSWORD',
64 | message: '该用户已存在,密码输入错误',
65 | }
66 | } else {
67 | message = '登录成功'
68 | }
69 | }
70 |
71 | user = JSON.parse(JSON.stringify(user))
72 | delete user.password
73 | ctx.status = 201
74 |
75 | // token
76 | // 设置 7 天过期时间
77 | // const expires = moment().add('days', 7).valueOf()
78 | // 生成 token 用户标识
79 | // const token = jwt.encode({
80 | // iss: user._id,
81 | // exp: expires
82 | // }, 'majun')
83 |
84 | // session
85 | ctx.session.admin_id = user.id;
86 | // this.ctx.session.maxAge = 3 * 24 * 3600 * 1000;
87 |
88 | ctx.body = {
89 | status: 1,
90 | // token,
91 | // expires,
92 | data: user,
93 | message,
94 | }
95 | }
96 |
97 | // GET /admin/info
98 | async getAdminInfo() {
99 | // 模拟单元测试
100 | // const ctx = this.ctx
101 | // const status = await ctx.service.shopping.category.getCategories()
102 | // console.log('[test]', status)
103 | // ctx.body = status
104 | // return
105 | const ctx = this.ctx
106 | const admin_id = ctx.session.admin_id;
107 | if (!admin_id || !Number(admin_id)) {
108 | ctx.body = {
109 | status: 0,
110 | message: '获取管理员信息失败'
111 | }
112 | return
113 | }
114 | try {
115 | const info = await ctx.model.Admin.findOne({
116 | id: admin_id
117 | }, '-_id -__v -password')
118 | if (!info) {
119 | throw new Error('未找到当前管理员')
120 | } else {
121 | ctx.body = {
122 | status: 1,
123 | data: info
124 | }
125 | }
126 | } catch (err) {
127 | ctx.body = {
128 | status: 0,
129 | message: '获取管理员信息失败'
130 | }
131 | }
132 | }
133 |
134 | // GET /admin/signout
135 | async signout() {
136 | const ctx = this.ctx
137 | try {
138 | delete ctx.session.admin_id;
139 | ctx.body = {
140 | status: 1,
141 | success: '退出成功'
142 | }
143 | } catch (err) {
144 | ctx.body = {
145 | status: 0,
146 | message: '退出失败'
147 | }
148 |
149 | }
150 | }
151 |
152 | // GET /admin/all
153 | async getAllAdmin() {
154 | const ctx = this.ctx
155 | const { limit = 20, offset = 0 } = ctx.request.body
156 | try {
157 | const allAdmin = await ctx.model.Admin.find({}, '-_id -password').sort({ id: -1 }).skip(Number(offset)).limit(Number(limit))
158 | ctx.body = {
159 | status: 1,
160 | data: allAdmin
161 | }
162 | } catch (err) {
163 | ctx.body = {
164 | status: 0,
165 | message: '获取管理列表失败'
166 | }
167 | }
168 | }
169 |
170 | // GET /admin/count
171 | async getAdminCount() {
172 | const ctx = this.ctx
173 | try {
174 | const count = await ctx.model.Admin.count()
175 | ctx.body = {
176 | status: 1,
177 | count,
178 | }
179 | } catch (err) {
180 | ctx.body = {
181 | status: 0,
182 | message: '获取管理员数量失败'
183 | }
184 | }
185 | }
186 |
187 | async register() {}
188 |
189 | async updateAvatar() {
190 | const ctx = this.ctx
191 | const admin_id = ctx.params.admin_id;
192 |
193 | if (!admin_id || !Number(admin_id)) {
194 | console.log('admin_id参数错误', admin_id)
195 | ctx.body = {
196 | status: 0,
197 | type: 'ERROR_ADMINID',
198 | message: 'admin_id参数错误',
199 | }
200 | return
201 | }
202 |
203 | try {
204 | const image_path = await ctx.service.upload.getPath(ctx);
205 | await ctx.model.Admin.findOneAndUpdate({ id: admin_id }, { $set: { avatar: image_path } });
206 | ctx.body = {
207 | status: 1,
208 | image_path,
209 | }
210 | return
211 | } catch (err) {
212 | console.log('上传图片失败', err);
213 | ctx.body = {
214 | status: 0,
215 | type: 'ERROR_UPLOAD_IMG',
216 | message: '上传图片失败'
217 | }
218 | return
219 | }
220 | }
221 |
222 | }
223 |
224 | module.exports = AdminService
--------------------------------------------------------------------------------
/app/service/member/vipCart.js:
--------------------------------------------------------------------------------
1 | const Service = require('egg').Service
2 |
3 | class VipCartService extends Service {
4 | async useCart() {
5 | this.ctx.body = {
6 | status: 0,
7 | type: 'INVALID_CART',
8 | message: '无效的卡号'
9 | }
10 | }
11 | }
12 |
13 | module.exports = VipCartService
--------------------------------------------------------------------------------
/app/service/promotion/hongbao.js:
--------------------------------------------------------------------------------
1 | const Service = require('egg').Service
2 |
3 | class HongbaoService extends Service {
4 | async getHongbao(type) {
5 | const ctx = this.ctx
6 | const present_status = type == 'intime' ? 1 : 4;
7 | const user_id = ctx.params.user_id;
8 | const { limit = 0, offset = 0 } = ctx.query
9 |
10 | try {
11 | if (!user_id || !Number(user_id)) {
12 | throw new Error('user_id参数错误')
13 | } else if (!Number(limit)) {
14 | throw new Error('limit参数错误')
15 | } else if (typeof Number(offset) !== 'number') {
16 | throw new Error('offset参数错误')
17 | }
18 | } catch (err) {
19 | console.log(err.message, err);
20 | ctx.body = {
21 | status: 0,
22 | type: 'ERROR_PARAMS',
23 | message: err.message
24 | }
25 | return
26 | }
27 |
28 | try {
29 | const hongbaos = await ctx.model.Hongbao.find({ present_status }, '-_id').limit(Number(limit)).skip(Number(offset));
30 | ctx.body = hongbaos
31 | } catch (err) {
32 | console.log('获取红包数据失败');
33 | ctx.body = {
34 | status: 0,
35 | type: 'ERROR_TO_GET_HONGBAO_DATA',
36 | message: '获取红包数据失败'
37 | }
38 | }
39 | }
40 |
41 | async exchange(req, res, next) {
42 | this.ctx.body = {
43 | status: 0,
44 | type: 'NOT_ALLOWD_API',
45 | message: '无效的兑换码'
46 | }
47 | }
48 | }
49 |
50 | module.exports = HongbaoService
--------------------------------------------------------------------------------
/app/service/shopping/category.js:
--------------------------------------------------------------------------------
1 | const Service = require('egg').Service;
2 |
3 | class FoodService extends Service {
4 | // GET /shopping/v2/restaurant/category
5 | async getCategories() {
6 | try {
7 | const categories = await this.ctx.model.Category.find({}, '-_id')
8 | this.ctx.body = categories
9 | } catch (err) {
10 | res.send({
11 | status: 0,
12 | type: 'ERROR_DATA',
13 | message: '获取categories失败:' + err
14 | })
15 | }
16 | }
17 |
18 | async addCategory(type) {
19 | try {
20 | await this.ctx.model.Category.addCategory(type)
21 | } catch (err) {
22 | console.log('增加category数量失败', err);
23 | }
24 | }
25 |
26 | async findById(id) {
27 | try {
28 | const CateEntity = await this.ctx.model.Category.findOne({ 'sub_categories.id': id })
29 | let categoName = CateEntity.name
30 | CateEntity.sub_categories.forEach(item => {
31 | if (item.id == id) {
32 | categoName += '/' + item.name;
33 | }
34 | })
35 | return categoName
36 | } catch (err) {
37 | console.log('通过category id获取数据失败')
38 | throw new Error(err)
39 | }
40 | }
41 |
42 | async getDelivery() {
43 | const ctx = this.ctx
44 | try {
45 | const deliveries = await ctx.model.Delivery.find({}, '-_id');
46 | ctx.body = deliveries
47 | } catch (err) {
48 | console.log('获取配送方式数据失败');
49 | ctx.body = {
50 | status: 0,
51 | type: 'ERROR_DATA',
52 | message: '获取配送方式数据失败'
53 | }
54 | }
55 | }
56 |
57 | async getActivity() {
58 | const ctx = this.ctx
59 | try {
60 | const activities = await ctx.model.Activity.find({}, '-_id');
61 | ctx.body = activities
62 | } catch (err) {
63 | console.log('获取活动数据失败');
64 | ctx.body = {
65 | status: 0,
66 | type: 'ERROR_DATA',
67 | message: '获取活动数据失败'
68 | }
69 | }
70 | }
71 | }
72 |
73 |
74 | module.exports = FoodService;
--------------------------------------------------------------------------------
/app/service/shopping/food.js:
--------------------------------------------------------------------------------
1 | const Service = require('egg').Service;
2 |
3 | const defaultData = [{
4 | name: '热销榜',
5 | description: '大家喜欢吃,才叫真好吃。',
6 | icon_url: "5da3872d782f707b4c82ce4607c73d1ajpeg",
7 | is_selected: true,
8 | type: 1,
9 | foods: [],
10 | }, {
11 | name: '优惠',
12 | description: '美味又实惠, 大家快来抢!',
13 | icon_url: "4735c4342691749b8e1a531149a46117jpeg",
14 | type: 1,
15 | foods: [],
16 | }]
17 |
18 | class FoodService extends Service {
19 | async initData(restaurant_id) {
20 | const ctx = this.ctx
21 | for (let i = 0; i < defaultData.length; i++) {
22 | let category_id;
23 | try {
24 | category_id = await ctx.helper.getId('category_id')
25 | } catch (err) {
26 | console.log('获取category_id失败');
27 | throw new Error(err);
28 | }
29 | const defaultItem = defaultData[i];
30 | const Category = { ...defaultItem, id: category_id, restaurant_id }
31 |
32 | try {
33 | const newFood = await ctx.model.Menu.create(Category)
34 | console.log('初始化食品数据成功');
35 | } catch (err) {
36 | console.log('初始化食品数据失败');
37 | throw new Error(err);
38 | }
39 | }
40 |
41 | }
42 |
43 | async getCategory() {
44 | const ctx = this.ctx
45 | const restaurant_id = ctx.params.restaurant_id
46 | try {
47 | const category_list = await ctx.model.Menu.find({ restaurant_id })
48 | ctx.body = {
49 | status: 1,
50 | category_list,
51 | }
52 |
53 | } catch (err) {
54 | console.log('获取餐馆食品种类失败');
55 | ctx.body = {
56 | status: 0,
57 | type: 'ERROR_GET_DATA',
58 | message: '获取数据失败'
59 | }
60 | }
61 |
62 | }
63 |
64 | async addCategory() {
65 | const ctx = this.ctx
66 | const fields = ctx.request.body
67 |
68 | try {
69 | if (!fields.name) {
70 | throw new Error('必须填写食品类型名称');
71 | } else if (!fields.restaurant_id) {
72 | throw new Error('餐馆ID错误');
73 | }
74 | } catch (err) {
75 | console.log(err.message, err);
76 | ctx.body = {
77 | status: 0,
78 | type: 'ERROR_PARAMS',
79 | message: err.message
80 | }
81 | return
82 | }
83 |
84 | let category_id;
85 | try {
86 | category_id = await ctx.helper.getId('category_id');
87 | } catch (err) {
88 | console.log('获取category_id失败');
89 | ctx.body = {
90 | type: 'ERROR_DATA',
91 | message: '获取数据失败'
92 | }
93 | return
94 | }
95 |
96 | const foodObj = {
97 | name: fields.name,
98 | description: fields.description,
99 | restaurant_id: fields.restaurant_id,
100 | id: category_id,
101 | foods: [],
102 | }
103 |
104 | try {
105 | const newFood = await ctx.model.Menu.create(foodObj)
106 | ctx.body = {
107 | status: 1,
108 | success: '添加食品种类成功',
109 | }
110 | } catch (err) {
111 | console.log('保存数据失败');
112 | ctx.body = {
113 | status: 0,
114 | type: 'ERROR_IN_SAVE_DATA',
115 | message: '保存数据失败',
116 | }
117 | }
118 | }
119 |
120 | async addFood() {
121 | const ctx = this.ctx
122 | const fields = ctx.request.body
123 |
124 | try {
125 | if (!fields.name) {
126 | throw new Error('必须填写食品名称');
127 | } else if (!fields.image_path) {
128 | throw new Error('必须上传食品图片');
129 | } else if (!fields.specs.length) {
130 | throw new Error('至少填写一种规格');
131 | } else if (!fields.category_id) {
132 | throw new Error('食品类型ID错误');
133 | } else if (!fields.restaurant_id) {
134 | throw new Error('餐馆ID错误');
135 | }
136 | } catch (err) {
137 | console.log('前台参数错误', err.message);
138 | ctx.body = {
139 | status: 0,
140 | type: 'ERROR_PARAMS',
141 | message: err.message
142 | }
143 | return
144 | }
145 |
146 | let category;
147 | let restaurant;
148 | try {
149 | category = await ctx.model.Menu.findOne({ id: fields.category_id });
150 | restaurant = await ctx.model.Shop.findOne({ id: fields.restaurant_id });
151 | } catch (err) {
152 | console.log('获取食品类型和餐馆信息失败');
153 | ctx.body = {
154 | status: 0,
155 | type: 'ERROR_DATA',
156 | message: '添加食品失败'
157 | }
158 | return
159 | }
160 |
161 | let item_id;
162 | try {
163 | item_id = await ctx.helper.getId('item_id');
164 | } catch (err) {
165 | console.log('获取item_id失败');
166 | ctx.body = {
167 | status: 0,
168 | type: 'ERROR_DATA',
169 | message: '添加食品失败'
170 | }
171 | return
172 | }
173 |
174 | const rating_count = Math.ceil(Math.random() * 1000);
175 | const month_sales = Math.ceil(Math.random() * 1000);
176 | const tips = rating_count + "评价 月售" + month_sales + "份";
177 | const newFood = {
178 | name: fields.name,
179 | description: fields.description,
180 | image_path: fields.image_path,
181 | activity: null,
182 | attributes: [],
183 | restaurant_id: fields.restaurant_id,
184 | category_id: fields.category_id,
185 | satisfy_rate: Math.ceil(Math.random() * 100),
186 | satisfy_count: Math.ceil(Math.random() * 1000),
187 | item_id,
188 | rating: (4 + Math.random()).toFixed(1),
189 | rating_count,
190 | month_sales,
191 | tips,
192 | specfoods: [],
193 | specifications: [],
194 | }
195 |
196 | if (fields.activity) {
197 | newFood.activity = {
198 | image_text_color: 'f1884f',
199 | icon_color: 'f07373',
200 | image_text: fields.activity,
201 | }
202 | }
203 |
204 | if (fields.attributes.length) {
205 | fields.attributes.forEach(item => {
206 | let attr;
207 | switch (item) {
208 | case '新':
209 | attr = {
210 | icon_color: '5ec452',
211 | icon_name: '新'
212 | }
213 | break;
214 | case '招牌':
215 | attr = {
216 | icon_color: 'f07373',
217 | icon_name: '招牌'
218 | }
219 | break;
220 | }
221 | newFood.attributes.push(attr);
222 | })
223 | }
224 |
225 | try {
226 | const [specfoods, specifications] = await this.getSpecfoods(fields, item_id);
227 | newFood.specfoods = specfoods;
228 | newFood.specifications = specifications;
229 | } catch (err) {
230 | console.log('添加specs失败', err);
231 | ctx.body = {
232 | status: 0,
233 | type: 'ERROR_DATA',
234 | message: '添加食品失败'
235 | }
236 | return
237 | }
238 |
239 | try {
240 | const foodEntity = await ctx.model.Food.create(newFood);
241 | category.foods.push(foodEntity);
242 | category.markModified('foods');
243 | await category.save();
244 | ctx.body = {
245 | status: 1,
246 | success: '添加食品成功',
247 | }
248 | } catch (err) {
249 | console.log('保存食品到数据库失败', err);
250 | ctx.body = {
251 | status: 0,
252 | type: 'ERROR_DATA',
253 | message: '添加食品失败'
254 | }
255 | }
256 |
257 | }
258 |
259 | async getSpecfoods(fields, item_id) {
260 | const ctx = this.ctx
261 | let specfoods = [],
262 | specifications = [];
263 | if (fields.specs.length < 2) {
264 | let food_id, sku_id;
265 | try {
266 | sku_id = await ctx.helper.getId('sku_id');
267 | food_id = await ctx.helper.getId('food_id');
268 | } catch (err) {
269 | console.log(err)
270 | throw new Error('获取sku_id、food_id失败')
271 | }
272 | specfoods.push({
273 | packing_fee: fields.specs[0].packing_fee,
274 | price: fields.specs[0].price,
275 | specs: [],
276 | specs_name: fields.specs[0].specs,
277 | name: fields.name,
278 | item_id,
279 | sku_id,
280 | food_id,
281 | restaurant_id: fields.restaurant_id,
282 | recent_rating: (Math.random() * 5).toFixed(1),
283 | recent_popularity: Math.ceil(Math.random() * 1000),
284 | })
285 | } else {
286 | specifications.push({
287 | values: [],
288 | name: "规格"
289 | })
290 | for (let i = 0; i < fields.specs.length; i++) {
291 | let food_id, sku_id;
292 | try {
293 | sku_id = await ctx.helper.getId('sku_id');
294 | food_id = await ctx.helper.getId('food_id');
295 | } catch (err) {
296 | throw new Error('获取sku_id、food_id失败')
297 | }
298 | specfoods.push({
299 | packing_fee: fields.specs[i].packing_fee,
300 | price: fields.specs[i].price,
301 | specs: [{
302 | name: "规格",
303 | value: fields.specs[i].specs
304 | }],
305 | specs_name: fields.specs[i].specs,
306 | name: fields.name,
307 | item_id,
308 | sku_id,
309 | food_id,
310 | restaurant_id: fields.restaurant_id,
311 | recent_rating: (Math.random() * 5).toFixed(1),
312 | recent_popularity: Math.ceil(Math.random() * 1000),
313 | })
314 | specifications[0].values.push(fields.specs[i].specs);
315 | }
316 | }
317 | return [specfoods, specifications]
318 | }
319 |
320 | async getMenu() {
321 | const ctx = this.ctx
322 | const restaurant_id = ctx.query.restaurant_id;
323 | const allMenu = ctx.query.allMenu;
324 |
325 | if (!restaurant_id || !Number(restaurant_id)) {
326 | console.log('获取餐馆参数ID错误');
327 | ctx.body = {
328 | status: 0,
329 | type: 'ERROR_PARAMS',
330 | message: '餐馆ID参数错误',
331 | }
332 | return
333 | }
334 |
335 | let filter;
336 | if (allMenu) {
337 | filter = { restaurant_id }
338 | } else {
339 | filter = { restaurant_id, $where: function() { return this.foods.length } };
340 | }
341 |
342 | try {
343 | const menu = await ctx.model.Menu.find(filter, '-_id');
344 | ctx.body = menu;
345 | } catch (err) {
346 | console.log('获取食品数据失败', err);
347 | ctx.body = {
348 | status: 0,
349 | type: 'GET_DATA_ERROR',
350 | message: '获取食品数据失败'
351 | }
352 | }
353 | }
354 |
355 | async getMenuDetail() {
356 | const ctx = this.ctx
357 | const category_id = ctx.params.category_id;
358 |
359 | if (!category_id || !Number(category_id)) {
360 | console.log('获取Menu详情参数ID错误');
361 | ctx.body = {
362 | status: 0,
363 | type: 'ERROR_PARAMS',
364 | message: 'Menu ID参数错误',
365 | }
366 | return
367 | }
368 |
369 | try {
370 | const menu = await ctx.model.Menu.findOne({ id: category_id }, '-_id');
371 | ctx.body = menu
372 | } catch (err) {
373 | console.log('获取Menu详情失败', err);
374 | ctx.body = {
375 | status: 0,
376 | type: 'GET_DATA_ERROR',
377 | message: '获取Menu详情失败'
378 | }
379 | }
380 |
381 | }
382 |
383 | async getFoods() {
384 | const ctx = this.ctx
385 | const { restaurant_id, limit = 20, offset = 0 } = ctx.query;
386 | try {
387 | let filter = {};
388 | if (restaurant_id && Number(restaurant_id)) {
389 | filter = { restaurant_id }
390 | }
391 | const foods = await ctx.model.Food.find(filter, '-_id').sort({ item_id: -1 }).limit(Number(limit)).skip(Number(offset));
392 | ctx.body = foods;
393 | } catch (err) {
394 | console.log('获取食品数据失败', err);
395 | ctx.body = {
396 | status: 0,
397 | type: 'GET_DATA_ERROR',
398 | message: '获取食品数据失败'
399 | }
400 | }
401 | }
402 |
403 | async getFoodsCount() {
404 | const ctx = this.ctx
405 | const restaurant_id = ctx.query.restaurant_id
406 | try {
407 | let filter = {};
408 | if (restaurant_id && Number(restaurant_id)) {
409 | filter = { restaurant_id }
410 | }
411 | const count = await ctx.model.Food.find(filter).count();
412 | ctx.body = {
413 | status: 1,
414 | count,
415 | }
416 | } catch (err) {
417 | console.log('获取食品数量失败', err);
418 | ctx.body = {
419 | status: 0,
420 | type: 'ERROR_TO_GET_COUNT',
421 | message: '获取食品数量失败'
422 | }
423 | }
424 | }
425 |
426 | async updateFood() {
427 | const ctx = this.ctx
428 | const fields = ctx.request.body
429 | const { name, item_id, description = "", image_path, category_id, new_category_id } = fields;
430 | try {
431 | if (!name) {
432 | throw new Error('食品名称错误');
433 | } else if (!item_id || !Number(item_id)) {
434 | throw new Error('食品ID错误');
435 | } else if (!category_id || !Number(category_id)) {
436 | throw new Error('食品分类ID错误');
437 | } else if (!image_path) {
438 | throw new Error('食品图片地址错误');
439 | }
440 |
441 | const [specfoods, specifications] = await this.getSpecfoods(fields, item_id);
442 |
443 | let newData;
444 | if (new_category_id !== category_id) {
445 | newData = { name, description, image_path, category_id: new_category_id, specfoods, specifications };
446 |
447 | const food = await ctx.model.Food.findOneAndUpdate({ item_id }, { $set: newData });
448 |
449 | const menu = await ctx.model.Menu.findOne({ id: category_id })
450 | const targetmenu = await ctx.model.Menu.findOne({ id: new_category_id })
451 | let subFood = menu.foods.id(food._id);
452 | subFood.set(newData)
453 | targetmenu.foods.push(subFood)
454 | targetmenu.markModified('foods');
455 | await targetmenu.save()
456 | await subFood.remove()
457 | await menu.save()
458 | } else {
459 | newData = { name, description, image_path, specfoods, specifications };
460 |
461 | const food = await ctx.model.Food.findOneAndUpdate({ item_id }, { $set: newData });
462 |
463 | const menu = await ctx.model.Menu.findOne({ id: category_id })
464 | let subFood = menu.foods.id(food._id);
465 | // ?
466 | subFood.set(newData)
467 | await menu.save()
468 | }
469 |
470 | ctx.body = {
471 | status: 1,
472 | success: '修改食品信息成功',
473 | }
474 | } catch (err) {
475 | console.log(err.message, err);
476 | ctx.body = {
477 | status: 0,
478 | type: 'ERROR_UPDATE_FOOD',
479 | message: '更新食品信息失败',
480 | }
481 | }
482 |
483 | }
484 |
485 | async deleteFood() {
486 | const ctx = this.ctx
487 | const food_id = ctx.params.food_id
488 | if (!food_id || !Number(food_id)) {
489 | console.log('food_id参数错误');
490 | ctx.body = {
491 | status: 0,
492 | type: 'ERROR_PARAMS',
493 | message: 'food_id参数错误',
494 | }
495 | return
496 | }
497 | try {
498 | const food = await ctx.model.Food.findOne({ item_id: food_id });
499 | const menu = await ctx.model.Menu.findOne({ id: food.category_id })
500 | let subFood = menu.foods.id(food._id);
501 | await subFood.remove()
502 | await menu.save()
503 | await food.remove()
504 | ctx.body = {
505 | status: 1,
506 | success: '删除食品成功',
507 | }
508 | } catch (err) {
509 | console.log('删除食品失败', err);
510 | ctx.body = {
511 | status: 0,
512 | type: 'DELETE_FOOD_FAILED',
513 | message: '删除食品失败',
514 | }
515 | }
516 |
517 | }
518 | }
519 |
520 |
521 | module.exports = FoodService;
--------------------------------------------------------------------------------
/app/service/statis/statis.js:
--------------------------------------------------------------------------------
1 | const Service = require('egg').Service
2 |
3 | class StatisService extends Service {
4 | async apiCount() {}
5 |
6 | async apiAllCount() {}
7 |
8 | async allApiRecord() {}
9 |
10 | async userCount() {
11 | const ctx = this.ctx
12 | const date = ctx.params.date;
13 | if (!date) {
14 | console.log('参数错误')
15 | ctx.body = {
16 | status: 0,
17 | type: 'ERROR_PARAMS',
18 | message: '参数错误'
19 | }
20 | return
21 | }
22 | try {
23 | const count = await ctx.model.UserInfo.find({ registe_time: eval('/^' + date + '/gi') }).count()
24 | ctx.body = {
25 | status: 1,
26 | count,
27 | }
28 | } catch (err) {
29 | console.log('获取当天注册人数失败');
30 | ctx.body = {
31 | status: 0,
32 | type: 'ERROR_GET_USER_REGISTE_COUNT',
33 | message: '获取当天注册人数失败'
34 | }
35 | }
36 | }
37 |
38 | async adminCount() {
39 | const ctx = this.ctx
40 | const date = ctx.params.date
41 |
42 | if (!date) {
43 | console.log('参数错误')
44 | ctx.body = {
45 | status: 0,
46 | type: 'ERROR_PARAMS',
47 | message: '参数错误'
48 | }
49 | return
50 | }
51 |
52 | try {
53 | const count = await ctx.model.Admin.find({ create_time: eval('/^' + date + '/gi') }).count()
54 | ctx.body = {
55 | status: 1,
56 | count,
57 | }
58 | } catch (err) {
59 | console.log('获取当天注册管理员人数失败');
60 | ctx.body = {
61 | status: 0,
62 | type: 'ERROR_GET_ADMIN_REGISTE_COUNT',
63 | message: '获取当天注册管理员人数失败'
64 | }
65 | }
66 |
67 | }
68 |
69 | async orderCount() {
70 | const ctx = this.ctx
71 | const date = ctx.params.date;
72 |
73 | if (!date) {
74 | console.log('参数错误')
75 | ctx.body = {
76 | status: 0,
77 | type: 'ERROR_PARAMS',
78 | message: '参数错误'
79 | }
80 | return
81 | }
82 |
83 | try {
84 | const count = await ctx.model.Order.find({ formatted_created_at: eval('/^' + date + '/gi') }).count()
85 | ctx.body = {
86 | status: 1,
87 | count,
88 | }
89 | } catch (err) {
90 | console.log('获取当天订单数量失败');
91 | ctx.body = {
92 | status: 0,
93 | type: 'ERROR_GET_ORDER_COUNT',
94 | message: '获取当天订单数量失败'
95 | }
96 | }
97 | }
98 |
99 | }
100 |
101 | module.exports = StatisService
--------------------------------------------------------------------------------
/app/service/ugc/rating.js:
--------------------------------------------------------------------------------
1 | const Service = require('egg').Service;
2 | const type = ['ratings', 'scores', 'tags'];
3 |
4 | class RatingService extends Service {
5 | async initData(restaurant_id) {
6 | const ctx = this.ctx
7 | try {
8 | const status = ctx.model.Rating.initData(restaurant_id)
9 | if (status) {
10 | console.log('初始化评论数据成功');
11 | }
12 | } catch (err) {
13 | console.log('初始化评论数据失败');
14 | throw new Error(err);
15 | }
16 | }
17 |
18 | async getRatings() {
19 | const ctx = this.ctx
20 | const restaurant_id = ctx.params.restaurant_id;
21 |
22 | if (!restaurant_id || !Number(restaurant_id)) {
23 | ctx.body = {
24 | status: 0,
25 | type: 'ERROR_PARAMS',
26 | message: '餐馆ID参数错误'
27 | }
28 | return
29 | }
30 |
31 | try {
32 | const ratings = await ctx.model.Rating.getData(restaurant_id, type[0]);
33 | ctx.body = ratings
34 | } catch (err) {
35 | console.log('获取评论列表失败', err);
36 | ctx.body = {
37 | status: 0,
38 | type: "ERROR_DATA",
39 | message: '未找到当前餐馆的评论数据'
40 | }
41 | }
42 | }
43 |
44 | async getScores() {
45 | const ctx = this.ctx
46 | const restaurant_id = ctx.params.restaurant_id;
47 |
48 | if (!restaurant_id || !Number(restaurant_id)) {
49 | ctx.body = {
50 | status: 0,
51 | type: 'ERROR_PARAMS',
52 | message: '餐馆ID参数错误'
53 | }
54 | return
55 | }
56 |
57 | try {
58 | const scores = await ctx.model.Rating.getData(restaurant_id, type[1]);
59 | ctx.body = scores
60 | } catch (err) {
61 | console.log('获取评论列表失败', err);
62 | ctx.body = {
63 | status: 0,
64 | type: "ERROR_DATA",
65 | message: '未找到当前餐馆的评论数据'
66 | }
67 | }
68 |
69 | }
70 |
71 | async getTags() {
72 | const ctx = this.ctx
73 | const restaurant_id = ctx.params.restaurant_id;
74 |
75 | if (!restaurant_id || !Number(restaurant_id)) {
76 | ctx.body = {
77 | status: 0,
78 | type: 'ERROR_PARAMS',
79 | message: '餐馆ID参数错误'
80 | }
81 | return
82 | }
83 |
84 | try {
85 | const tags = await ctx.model.Rating.getData(restaurant_id, type[2]);
86 | ctx.body = tags
87 | } catch (err) {
88 | console.log('获取评论列表失败', err);
89 | ctx.body = {
90 | status: 0,
91 | type: "ERROR_DATA",
92 | message: '未找到当前餐馆的评论数据'
93 | }
94 | }
95 |
96 | }
97 |
98 | }
99 |
100 |
101 | module.exports = RatingService;
--------------------------------------------------------------------------------
/app/service/upload.js:
--------------------------------------------------------------------------------
1 | const Service = require('egg').Service;
2 | const path = require('path')
3 | const fs = require('fs')
4 | // const gm = require('gm')
5 |
6 | // const qiniu = require('qiniu')
7 | // qiniu.conf.ACCESS_KEY = 'Ep714TDrVhrhZzV2VJJxDYgGHBAX-KmU1xV1SQdS';
8 | // qiniu.conf.SECRET_KEY = 'XNIW2dNffPBdaAhvm9dadBlJ-H6yyCTIJLxNM_N6';
9 |
10 | class UploadService extends Service {
11 | async upload() {
12 | const ctx = this.ctx
13 | const type = ctx.params
14 | try {
15 | const image_path = await this.getPath()
16 | // const image_path=await this.qiniu()
17 | ctx.body = {
18 | status: 1,
19 | image_path
20 | }
21 | } catch (err) {
22 | console.log('上传图片失败', err);
23 | ctx.body = {
24 | status: 0,
25 | type: 'ERROR_UPLOAD_IMG',
26 | message: '上传图片失败'
27 | }
28 | }
29 | }
30 |
31 | async getPath() {
32 | const ctx = this.ctx
33 | let files = ctx.request.files[0]
34 | let img_id;
35 |
36 | console.log('[files]',JSON.stringify(files))
37 |
38 | try {
39 | img_id = await ctx.helper.getId('img_id')
40 | } catch (err) {
41 | console.log('获取图片id失败');
42 | fs.unlinkSync(files.filepath);
43 | // reject('获取图片id失败');
44 | }
45 |
46 | const extname = path.extname(files.filename)
47 |
48 | if (!['.jpg', '.jpge', '.png'].includes(extname)) {
49 | fs.unlinkSync(files.filepath);
50 | res.send({
51 | status: 0,
52 | type: 'ERROR_EXTNAME',
53 | message: '文件格式错误'
54 | })
55 | // reject('上传失败');
56 | return
57 | }
58 |
59 | const hashName = (new Date().getTime() + Math.ceil(Math.random() * 10000)).toString(16) + img_id
60 | const fullName = hashName + extname
61 | const repath = './app/public/temp/' + fullName
62 |
63 | try {
64 | // fs.renameSync(files.filepath, repath)
65 | let readStream = fs.createReadStream(files.filepath)
66 | let writeStream = fs.createWriteStream(repath)
67 | readStream.pipe(writeStream);
68 | readStream.on('end', function() {
69 | fs.unlinkSync(files.filepath);
70 | });
71 |
72 | // gm(repath).resize(200, 200, '!')
73 | // .write(repath, (err) => {
74 | // // resolve(fullName)
75 | // console.log('gm', err, fullName)
76 | // // return fullName
77 | // })
78 |
79 | return fullName
80 | } catch (err) {
81 | console.log('保存图片失败', err);
82 | if (fs.existsSync(repath)) {
83 | fs.unlinkSync(repath);
84 | } else {
85 | fs.unlinkSync(files.filepath);
86 | }
87 | // reject('保存图片失败')
88 | }
89 | }
90 |
91 | // async qiniu(req, type = 'default') {
92 | // return new Promise((resolve, reject) => {
93 | // const form = formidable.IncomingForm();
94 | // form.uploadDir = './public/img';
95 | // form.parse(req, async (err, fields, files) => {
96 | // let img_id;
97 | // try {
98 | // img_id = await this.getId('img_id');
99 | // } catch (err) {
100 | // console.log('获取图片id失败');
101 | // fs.unlinkSync(files.file.path);
102 | // reject('获取图片id失败')
103 | // }
104 | // const hashName = (new Date().getTime() + Math.ceil(Math.random() * 10000)).toString(16) + img_id;
105 | // const extname = path.extname(files.file.name);
106 | // const repath = './public/img/' + hashName + extname;
107 | // try {
108 | // const key = hashName + extname;
109 | // await fs.rename(files.file.path, repath);
110 | // const token = this.uptoken('node-elm', key);
111 | // const qiniuImg = await this.uploadFile(token.toString(), key, repath);
112 | // fs.unlinkSync(repath);
113 | // resolve(qiniuImg)
114 | // } catch (err) {
115 | // console.log('保存至七牛失败', err);
116 | // fs.unlinkSync(files.file.path)
117 | // reject('保存至七牛失败')
118 | // }
119 | // });
120 | // })
121 | // }
122 | // uptoken(bucket, key) {
123 | // var putPolicy = new qiniu.rs.PutPolicy(bucket + ":" + key);
124 | // return putPolicy.token();
125 | // }
126 | // uploadFile(uptoken, key, localFile) {
127 | // return new Promise((resolve, reject) => {
128 | // var extra = new qiniu.io.PutExtra();
129 | // qiniu.io.putFile(uptoken, key, localFile, extra, function(err, ret) {
130 | // if (!err) {
131 | // resolve(ret.key)
132 | // } else {
133 | // console.log('图片上传至七牛失败', err);
134 | // reject(err)
135 | // }
136 | // });
137 | // })
138 | // }
139 |
140 | }
141 |
142 | module.exports = UploadService;
--------------------------------------------------------------------------------
/app/service/v1/addre.js:
--------------------------------------------------------------------------------
1 | const Service = require('egg').Service
2 |
3 | class AddreService extends Service {
4 | async getAddress() {
5 | const ctx = this.ctx
6 | const user_id = ctx.params.user_id;
7 |
8 | if (!user_id || !Number(user_id)) {
9 | ctx.body = {
10 | type: 'ERROR_USER_ID',
11 | message: 'user_id参数错误',
12 | }
13 | return
14 | }
15 |
16 | try {
17 | const addressList = await ctx.model.Address.find({ user_id }, '-_id');
18 | ctx.body = addressList
19 | } catch (err) {
20 | console.log('获取收获地址失败', err);
21 | ctx.body = {
22 | type: 'ERROR_GET_ADDRESS',
23 | message: '获取地址列表失败'
24 | }
25 | }
26 |
27 | }
28 |
29 | async addAddress() {
30 | const ctx = this.ctx
31 | const user_id = ctx.params.user_id;
32 | const { address, address_detail, geohash, name, phone, phone_bk, poi_type = 0, sex, tag, tag_type } = ctx.request.body;
33 |
34 | try {
35 | if (!user_id || !Number(user_id)) {
36 | throw new Error('用户ID参数错误');
37 | } else if (!address) {
38 | throw new Error('地址信息错误');
39 | } else if (!address_detail) {
40 | throw new Error('详细地址信息错误');
41 | } else if (!geohash) {
42 | throw new Error('geohash参数错误');
43 | } else if (!name) {
44 | throw new Error('收货人姓名错误');
45 | } else if (!phone) {
46 | throw new Error('收获手机号错误');
47 | } else if (!sex) {
48 | throw new Error('性别错误');
49 | } else if (!tag) {
50 | throw new Error('标签错误');
51 | } else if (!tag_type) {
52 | throw new Error('标签类型错误');
53 | }
54 | } catch (err) {
55 | console.log(err.message);
56 | ctx.body = {
57 | status: 0,
58 | type: 'GET_WRONG_PARAM',
59 | message: err.message
60 | }
61 | return
62 | }
63 |
64 | try {
65 | const address_id = await ctx.helper.getId('address_id');
66 | const newAddress = {
67 | id: address_id,
68 | address,
69 | phone,
70 | phone_bk: phone_bk && phone_bk,
71 | name,
72 | st_geohash: geohash,
73 | address_detail,
74 | sex,
75 | tag,
76 | tag_type,
77 | user_id,
78 | }
79 | await ctx.model.Address.create(newAddress);
80 | ctx.body = {
81 | status: 1,
82 | success: '添加地址成功'
83 | }
84 | } catch (err) {
85 | console.log('添加地址失败', err);
86 | ctx.body = {
87 | status: 0,
88 | type: 'ERROR_ADD_ADDRESS',
89 | message: '添加地址失败'
90 | }
91 | }
92 |
93 |
94 | }
95 |
96 | async deleteAddress() {
97 | const ctx = this.ctx
98 | const { user_id, address_id } = ctx.params;
99 |
100 | if (!user_id || !Number(user_id) || !address_id || !Number(address_id)) {
101 | ctx.body = {
102 | type: 'ERROR_PARAMS',
103 | message: '参数错误',
104 | }
105 | return
106 | }
107 |
108 | try {
109 | await ctx.model.Address.findOneAndRemove({ id: address_id });
110 | ctx.body = {
111 | status: 1,
112 | success: '删除地址成功',
113 | }
114 | } catch (err) {
115 | console.log('删除收获地址失败', err);
116 | ctx.body = {
117 | type: 'ERROR_DELETE_ADDRESS',
118 | message: '删除收获地址失败'
119 | }
120 | }
121 | }
122 |
123 | async getAddAddressById() {
124 | const ctx = this.ctx
125 | const address_id = ctx.params.address_id;
126 | if (!address_id || !Number(address_id)) {
127 | ctx.body = {
128 | type: 'ERROR_PARAMS',
129 | message: '参数错误',
130 | }
131 | return
132 | }
133 | try {
134 | const address = await ctx.model.Address.findOne({ id: address_id });
135 | ctx.body = address
136 | } catch (err) {
137 | console.log('获取地址信息失败', err);
138 | ctx.body = {
139 | type: 'ERROR_GET_ADDRESS',
140 | message: '获取地址信息失败'
141 | }
142 | }
143 | }
144 |
145 | }
146 |
147 | module.exports = AddreService
--------------------------------------------------------------------------------
/app/service/v1/captchas.js:
--------------------------------------------------------------------------------
1 | const Service = require('egg').Service;
2 | const captchapng = require('captchapng')
3 |
4 | class CaptchasService extends Service {
5 | async getCaptchas() {
6 | const ctx = this.ctx
7 | const cap = parseInt(Math.random() * 9000 + 1000);
8 | const p = new captchapng(80, 30, cap);
9 | p.color(0, 0, 0, 0);
10 | p.color(80, 80, 80, 255);
11 | const base64 = p.getBase64();
12 | ctx.cookies.set('cap', cap, { maxAge: 300000, httpOnly: true });
13 | ctx.body = {
14 | status: 1,
15 | code: 'data:image/png;base64,' + base64
16 | }
17 | }
18 |
19 | }
20 |
21 |
22 | module.exports = CaptchasService;
--------------------------------------------------------------------------------
/app/service/v1/carts.js:
--------------------------------------------------------------------------------
1 | const Service = require('egg').Service
2 | const extra = [{
3 | description: '',
4 | name: '餐盒',
5 | price: 0,
6 | quantity: 1,
7 | type: 0,
8 | }]
9 |
10 | class CartsService extends Service {
11 | // 全部处理放在service,后期再抽象
12 | async checkout() {
13 | const ctx = this.ctx
14 | const UID = ctx.session.UID;
15 | const { come_from, geohash, entities = [], restaurant_id } = ctx.request.body;
16 |
17 | try {
18 | if (!(entities instanceof Array) || !entities.length) {
19 | throw new Error('entities参数错误')
20 | } else if (!(entities[0] instanceof Array) || !entities[0].length) {
21 | throw new Error('entities参数错误')
22 | } else if (!restaurant_id) {
23 | throw new Error('restaurant_id参数错误')
24 | }
25 | } catch (err) {
26 | console.log(err);
27 | ctx.body = {
28 | status: 0,
29 | type: 'ERROR_PARAMS',
30 | message: err.message
31 | }
32 | return
33 | }
34 |
35 | let payments; //付款方式
36 | let cart_id; //购物车id
37 | let restaurant; //餐馆详情
38 | let deliver_time; //配送时间
39 | let delivery_reach_time; //到达时间
40 | let from = geohash.split(',')[0] + ',' + geohash.split(',')[1];
41 |
42 | try {
43 | payments = await ctx.model.Payments.find({}, '-_id');
44 | cart_id = await ctx.helper.getId('cart_id');
45 | restaurant = await ctx.model.Shop.findOne({ id: restaurant_id });
46 | const to = restaurant.latitude + ',' + restaurant.longitude;
47 | deliver_time = await ctx.service.address.getDistance(from, to, 'tiemvalue');
48 | let time = new Date().getTime() + deliver_time * 1000;
49 | let hour = ('0' + new Date(time).getHours()).substr(-2);
50 | let minute = ('0' + new Date(time).getMinutes()).substr(-2);
51 | delivery_reach_time = hour + ':' + minute;
52 | } catch (err) {
53 | console.log('获取数据数据失败', err);
54 | ctx.body = {
55 | status: 0,
56 | type: 'ERROR_DATA',
57 | message: '添加购物车失败',
58 | }
59 | return
60 | }
61 |
62 | const deliver_amount = 4;
63 | let price = 0; //食品价格
64 | entities[0].map(item => {
65 | price += item.price * item.quantity;
66 | if (item.packing_fee) {
67 | extra[0].price += item.packing_fee * item.quantity;
68 | }
69 | if (item.specs[0]) {
70 | return item.name = item.name + '-' + item.specs[0];
71 | }
72 | })
73 |
74 | //食品总价格
75 | const total = price + extra[0].price * extra[0].quantity + deliver_amount;
76 |
77 | //是否支持发票
78 | let invoice = {
79 | is_available: false,
80 | status_text: "商家不支持开发票",
81 | };
82 | restaurant.supports.forEach(item => {
83 | if (item.icon_name == '票') {
84 | invoice = {
85 | is_available: true,
86 | status_text: "不需要开发票",
87 | };
88 | }
89 | })
90 |
91 | const checkoutInfo = {
92 | id: cart_id,
93 | cart: {
94 | id: cart_id,
95 | groups: entities,
96 | extra: extra,
97 | deliver_amount,
98 | is_deliver_by_fengniao: !!restaurant.delivery_mode,
99 | original_total: total,
100 | phone: restaurant.phone,
101 | restaurant_id,
102 | restaurant_info: restaurant,
103 | restaurant_minimum_order_amount: restaurant.float_minimum_order_amount,
104 | total,
105 | user_id: UID,
106 | },
107 | delivery_reach_time,
108 | invoice,
109 | sig: Math.ceil(Math.random() * 1000000).toString(),
110 | payments,
111 | }
112 |
113 | try {
114 | const cart = await ctx.model.Cart.create(checkoutInfo);
115 | ctx.body = cart
116 | } catch (err) {
117 | console.log('保存购物车数据失败');
118 | ctx.body = {
119 | status: 0,
120 | type: 'ERROR_TO_SAVE_CART',
121 | message: '加入购物车失败'
122 | }
123 | }
124 | }
125 |
126 | }
127 |
128 | module.exports = CartsService
--------------------------------------------------------------------------------
/app/service/v1/city.js:
--------------------------------------------------------------------------------
1 | const Service = require('egg').Service;
2 | const pinyin = require('pinyin')
3 |
4 | class CityService extends Service {
5 | async getCity() {
6 | const ctx = this.ctx
7 | const type = ctx.request.query.type
8 | let cityInfo
9 | try {
10 | switch (type) {
11 | case 'guess':
12 | const city = await this.getCityName()
13 | cityInfo = await ctx.model.City.cityGuess(city)
14 | break
15 | case 'hot':
16 | cityInfo = await ctx.model.City.cityHot()
17 | break
18 | case 'group':
19 | cityInfo = await ctx.model.City.cityGroup()
20 | break
21 | default:
22 | ctx.body = {
23 | name: 'ERROR_QUERY_TYPE',
24 | message: '参数错误',
25 | }
26 | return
27 | }
28 | ctx.body = cityInfo
29 | } catch (err) {
30 | ctx.body = {
31 | name: 'ERROR_DATA',
32 | message: '获取数据失败',
33 | }
34 | }
35 | }
36 |
37 | async getCityName() {
38 | const ctx = this.ctx
39 | let cityInfo
40 | try {
41 | cityInfo = await ctx.service.address.guessPosition()
42 | } catch (err) {
43 | this.ctx = {
44 | name: 'ERROR_DATA',
45 | message: '获取数据失败',
46 | }
47 | return
48 | }
49 | //汉字转换成拼音
50 | const pinyinArr = pinyin(cityInfo.city, {
51 | style: pinyin.STYLE_NORMAL
52 | })
53 | let cityName = ''
54 | pinyinArr.forEach(item => {
55 | cityName += item[0]
56 | })
57 | return cityName
58 | }
59 |
60 | async getCityById() {
61 | const ctx = this.ctx
62 | const cityid = ctx.params.id;
63 |
64 | if (isNaN(cityid)) {
65 | ctx.body = {
66 | name: 'ERROR_PARAM_TYPE',
67 | message: '参数错误',
68 | }
69 | return
70 | }
71 |
72 | try {
73 | const cityInfo = await ctx.model.City.getCityById(cityid);
74 | ctx.body = cityInfo
75 | } catch (err) {
76 | ctx.body = {
77 | name: 'ERROR_DATA',
78 | message: '获取数据失败',
79 | }
80 | }
81 |
82 | }
83 |
84 | async getExactAddress() {
85 |
86 | }
87 |
88 | async pois() {
89 | const ctx = this.ctx
90 | const geohash = ctx.params.geohash;
91 |
92 | try {
93 | if (geohash.indexOf(',') == -1) {
94 | throw new Error('参数错误')
95 | }
96 | } catch (err) {
97 | console.log('参数错误');
98 | ctx.body = {
99 | status: 0,
100 | type: 'ERROR_PARAMS',
101 | message: '参数错误',
102 | }
103 | return
104 | }
105 |
106 | const poisArr = geohash.split(',');
107 | try {
108 | const result = await ctx.service.address.getpois(poisArr[0], poisArr[1]);
109 | const address = {
110 | address: result.result.address,
111 | city: result.result.address_component.province,
112 | geohash,
113 | latitude: poisArr[0],
114 | longitude: poisArr[1],
115 | name: result.result.formatted_addresses.recommend,
116 | }
117 | ctx.body = address
118 | } catch (err) {
119 | console.log('getpois返回信息失败');
120 | ctx.body = {
121 | status: 0,
122 | type: 'ERROR_DATA',
123 | message: '获取数据失败',
124 | }
125 | }
126 |
127 | }
128 | }
129 |
130 |
131 | module.exports = CityService;
--------------------------------------------------------------------------------
/app/service/v1/order.js:
--------------------------------------------------------------------------------
1 | const Service = require('egg').Service
2 | const dtime = require('moment')
3 |
4 | class OrderService extends Service {
5 | async postOrder() {
6 | const ctx = this.ctx
7 | const { user_id, cart_id } = ctx.params;
8 | const { address_id, come_from = 'mobile_web', deliver_time = '', description, entities, geohash, paymethod_id = 1 } = ctx.request.body;
9 |
10 | try {
11 | if (!(entities instanceof Array) || !entities.length) {
12 | throw new Error('entities参数错误')
13 | } else if (!(entities[0] instanceof Array) || !entities[0].length) {
14 | throw new Error('entities参数错误')
15 | } else if (!address_id) {
16 | throw new Error('address_id参数错误')
17 | } else if (!user_id || !Number(user_id)) {
18 | throw new Error('user_id参数错误')
19 | } else if (!cart_id || !Number(cart_id)) {
20 | throw new Error('cart_id参数错误')
21 | } else if (!user_id) {
22 | throw new Error('未登录')
23 | }
24 | } catch (err) {
25 | console.log(err.message, err);
26 | ctx.body = {
27 | status: 0,
28 | type: 'ERROR_PARAMS',
29 | message: err.message
30 | }
31 | return
32 | }
33 |
34 | let cartDetail;
35 | let order_id;
36 |
37 | try {
38 | cartDetail = await ctx.model.Cart.findOne({ id: cart_id });
39 | order_id = await ctx.helper.getId('order_id');
40 | } catch (err) {
41 | console.log('获取数据失败', err);
42 | ctx.body = {
43 | status: 0,
44 | type: 'ERROR_GET_DATA',
45 | message: '获取订单失败',
46 | }
47 | return
48 | }
49 |
50 | const deliver_fee = { price: cartDetail.cart.deliver_amount };
51 | const orderObj = {
52 | basket: {
53 | group: entities,
54 | packing_fee: {
55 | name: cartDetail.cart.extra[0].name,
56 | price: cartDetail.cart.extra[0].price,
57 | quantity: cartDetail.cart.extra[0].quantity,
58 | },
59 | deliver_fee,
60 | },
61 | restaurant_id: cartDetail.cart.restaurant_id,
62 | restaurant_image_url: cartDetail.cart.restaurant_info.image_path,
63 | restaurant_name: cartDetail.cart.restaurant_info.name,
64 | formatted_created_at: dtime().format('YYYY-MM-DD HH:mm'),
65 | order_time: new Date().getTime(),
66 | time_pass: 900,
67 | status_bar: {
68 | color: 'f60',
69 | image_type: '',
70 | sub_title: '15分钟内支付',
71 | title: '',
72 | },
73 | total_amount: cartDetail.cart.total,
74 | total_quantity: entities[0].length,
75 | unique_id: order_id,
76 | id: order_id,
77 | user_id,
78 | address_id,
79 | }
80 |
81 | try {
82 | await ctx.model.Order.create(orderObj);
83 | ctx.body = {
84 | status: 1,
85 | success: '下单成功,请及时付款',
86 | need_validation: false,
87 | }
88 | } catch (err) {
89 | console.log('保存订单数据失败');
90 | ctx.body = {
91 | status: 0,
92 | type: 'ERROR_SAVE_ORDER',
93 | message: '保存订单失败'
94 | }
95 | }
96 |
97 | }
98 |
99 | async getOrders() {
100 | const ctx = this.ctx
101 | const user_id = ctx.params.user_id;
102 | const { limit = 0, offset = 0 } = ctx.query;
103 |
104 | try {
105 | if (!user_id || !Number(user_id)) {
106 | throw new Error('user_id参数错误')
107 | } else if (!Number(limit)) {
108 | throw new Error('limit参数错误')
109 | } else if (typeof Number(offset) !== 'number') {
110 | throw new Error('offset参数错误')
111 | }
112 | } catch (err) {
113 | console.log(err.message, err);
114 | ctx.body = {
115 | status: 0,
116 | type: 'ERROR_PARAMS',
117 | message: err.message
118 | }
119 | return
120 | }
121 |
122 | try {
123 | const orders = await ctx.model.Order.find({ user_id }).sort({ id: -1 }).limit(Number(limit)).skip(Number(offset));
124 | const timeNow = new Date().getTime();
125 | orders.map(item => {
126 | if (timeNow - item.order_time < 900000) {
127 | item.status_bar.title = '等待支付';
128 | } else {
129 | item.status_bar.title = '支付超时';
130 | }
131 | item.time_pass = Math.ceil((timeNow - item.order_time) / 1000);
132 | item.save()
133 | return item
134 | })
135 | ctx.body = orders
136 | } catch (err) {
137 | console.log('获取订单列表失败', err);
138 | ctx.body = {
139 | status: 0,
140 | type: 'ERROR_GET_ORDER_LIST',
141 | message: '获取订单列表失败'
142 | }
143 | }
144 |
145 | }
146 |
147 | async getDetail() {
148 | const ctx = this.ctx
149 | const { user_id, order_id } = ctx.params;
150 |
151 | try {
152 | if (!user_id || !Number(user_id)) {
153 | throw new Error('user_id参数错误')
154 | } else if (!order_id || !Number(order_id)) {
155 | throw new Error('order_id参数错误')
156 | }
157 | } catch (err) {
158 | console.log(err.message);
159 | ctx.body = {
160 | status: 0,
161 | type: 'GET_ERROR_PARAM',
162 | message: err.message,
163 | }
164 | return
165 | }
166 |
167 | try {
168 | const order = await ctx.model.Order.findOne({ id: order_id }, '-_id');
169 | const addressDetail = await ctx.model.Address.findOne({ id: order.address_id });
170 | const orderDetail = { ...order, ...{ addressDetail: addressDetail.address, consignee: addressDetail.name, deliver_time: '尽快送达', pay_method: '在线支付', phone: addressDetail.phone } };
171 | ctx.body = orderDetail
172 | } catch (err) {
173 | console.log('获取订单信息失败', err);
174 | ctx.body = {
175 | status: 0,
176 | type: 'ERROR_TO_GET_ORDER_DETAIL',
177 | message: '获取订单信息失败'
178 | }
179 | }
180 |
181 | }
182 |
183 | async getAllOrders() {
184 | const ctx = this.ctx
185 | const { restaurant_id, limit = 20, offset = 0 } = ctx.query;
186 | try {
187 | let filter = {};
188 | if (restaurant_id && Number(restaurant_id)) {
189 | filter = { restaurant_id }
190 | }
191 |
192 | const orders = await ctx.model.Order.find(filter).sort({ id: -1 }).limit(Number(limit)).skip(Number(offset));
193 |
194 | const timeNow = new Date().getTime();
195 | orders.map(item => {
196 | if (timeNow - item.order_time < 900000) {
197 | item.status_bar.title = '等待支付';
198 | } else {
199 | item.status_bar.title = '支付超时';
200 | }
201 | item.time_pass = Math.ceil((timeNow - item.order_time) / 1000);
202 | item.save()
203 | return item
204 | })
205 | ctx.body = orders
206 | } catch (err) {
207 | console.log('获取订单数据失败', err);
208 | ctx.body = {
209 | status: 0,
210 | type: 'GET_ORDER_DATA_ERROR',
211 | message: '获取订单数据失败'
212 | }
213 | }
214 | }
215 |
216 | async getOrdersCount() {
217 | const ctx = this.ctx
218 | const restaurant_id = ctx.query.restaurant_id;
219 | try {
220 | let filter = {};
221 | if (restaurant_id && Number(restaurant_id)) {
222 | filter = { restaurant_id }
223 | }
224 |
225 | const count = await ctx.model.Order.find(filter).count();
226 | ctx.body = {
227 | status: 1,
228 | count,
229 | }
230 | } catch (err) {
231 | console.log('获取订单数量失败', err);
232 | ctx.body = {
233 | status: 0,
234 | type: 'ERROR_TO_GET_COUNT',
235 | message: '获取订单数量失败'
236 | }
237 | }
238 | }
239 |
240 | }
241 |
242 | module.exports = OrderService
--------------------------------------------------------------------------------
/app/service/v1/remark.js:
--------------------------------------------------------------------------------
1 | const Service = require('egg').Service
2 |
3 | class RemarkService extends Service {
4 | // 全部处理放在service,后期再抽象
5 | async getRemarks() {
6 | const ctx = this.ctx
7 | const cart_id = ctx.params.cart_id;
8 |
9 | if (!cart_id || !Number(cart_id)) {
10 | ctx.body = {
11 | status: 0,
12 | type: 'ERROR_PARAMS',
13 | message: '购物车ID参数错误'
14 | }
15 | return
16 | }
17 |
18 | try {
19 | const remarks = await ctx.model.Remark.findOne({}, '-_id');
20 | ctx.body = remarks;
21 | } catch (err) {
22 | console.log('获取备注数据失败', err);
23 | ctx.body = {
24 | status: 0,
25 | type: 'ERROR_GET_DATA',
26 | message: '获取备注数据失败'
27 | }
28 | }
29 |
30 | }
31 |
32 | }
33 |
34 | module.exports = RemarkService
--------------------------------------------------------------------------------
/app/service/v1/search.js:
--------------------------------------------------------------------------------
1 | const Service = require('egg').Service
2 |
3 | class searchService extends Service {
4 | async search() {
5 | const ctx = this.ctx
6 | let { type = 'search', city_id, keyword } = ctx.request.query
7 | if (!keyword) {
8 | ctx.body = {
9 | name: 'ERROR_QUERY_TYPE',
10 | message: '缺少关键词',
11 | }
12 | return
13 | } else if (isNaN(city_id)) {
14 | try {
15 | const cityName = await ctx.service.v1.city.getCityName()
16 | const cityInfo = await ctx.model.City.cityGuess(cityName)
17 | city_id = cityInfo.id
18 | } catch (err) {
19 | ctx.body = {
20 | name: 'ERROR_GET_POSITION',
21 | message: '获取数据失败',
22 | }
23 | }
24 | }
25 | try {
26 | const cityInfo = await ctx.model.City.getCityById(city_id)
27 | const resObj = await ctx.service.address.searchPlace(keyword, cityInfo.name, type)
28 | const cityList = []
29 | resObj.data.forEach((item, index) => {
30 | cityList.push({
31 | name: item.title,
32 | address: item.address,
33 | latitude: item.location.lat,
34 | longitude: item.location.lng,
35 | geohash: item.location.lat + ',' + item.location.lng,
36 | })
37 | })
38 | ctx.body = cityList
39 | } catch (err) {
40 | ctx.body = {
41 | name: 'GET_ADDRESS_ERROR',
42 | message: '获取地址信息失败:'+ err,
43 | }
44 | }
45 | }
46 | }
47 |
48 | module.exports = searchService
--------------------------------------------------------------------------------
/app/service/v2/entry.js:
--------------------------------------------------------------------------------
1 | const Service = require('egg').Service
2 |
3 | class EntryService extends Service {
4 | async getEntry() {
5 | const ctx = this.ctx
6 | try {
7 | const entries = await ctx.model.Entry.find({}, '-_id');
8 | ctx.body = entries
9 | } catch (err) {
10 | console.log('获取数据失败');
11 | ctx.body = {
12 | status: 0,
13 | type: 'ERROR_DATA',
14 | message: '获取数据失败'
15 | }
16 | return
17 | }
18 |
19 | }
20 | }
21 |
22 | module.exports = EntryService
--------------------------------------------------------------------------------
/app/service/v2/user.js:
--------------------------------------------------------------------------------
1 | const Service = require('egg').Service
2 | const crypto = require('crypto')
3 | const dtime = require('moment')
4 |
5 | class UserService extends Service {
6 | async login() {
7 | const ctx = this.ctx
8 | const cap = ctx.cookies.get('cap')
9 | const fields = ctx.request.body
10 |
11 | if (!cap) {
12 | console.log('验证码失效', cap)
13 | ctx.body = {
14 | status: 0,
15 | type: 'ERROR_CAPTCHA',
16 | message: '验证码失效',
17 | }
18 | return
19 | }
20 |
21 | const { username, password, captcha_code } = fields;
22 | try {
23 | if (!username) {
24 | throw new Error('用户名参数错误');
25 | } else if (!password) {
26 | throw new Error('密码参数错误');
27 | } else if (!captcha_code) {
28 | throw new Error('验证码参数错误');
29 | }
30 | } catch (err) {
31 | console.log('登陆参数错误', err);
32 | ctx.body = {
33 | status: 0,
34 | type: 'ERROR_QUERY',
35 | message: err.message,
36 | }
37 | return
38 | }
39 | if (cap.toString() !== captcha_code.toString()) {
40 | ctx.body = {
41 | status: 0,
42 | type: 'ERROR_CAPTCHA',
43 | message: '验证码不正确',
44 | }
45 | return
46 | }
47 |
48 | const newpassword = this.encryption(password);
49 | try {
50 | const user = await ctx.model.User.findOne({ username });
51 | if (!user) {
52 | const user_id = await ctx.helper.getId('user_id');
53 | const cityInfo = await ctx.service.address.guessPosition(ctx.request.body);
54 | const registe_time = dtime().format('YYYY-MM-DD HH:mm');
55 | const newUser = { username, password: newpassword, user_id };
56 | const newUserInfo = { username, user_id, id: user_id, city: cityInfo.city, registe_time, };
57 | try {
58 | await ctx.model.User.create(newUser);
59 | const userinfo = await ctx.model.UserInfo.create(newUserInfo);
60 | ctx.session.user_id = user_id;
61 | ctx.body = userinfo;
62 | } catch (err) {
63 | console.log(err)
64 | }
65 | } else if (user.password.toString() !== newpassword.toString()) {
66 | console.log('用户登录密码错误')
67 | ctx.body = {
68 | status: 0,
69 | type: 'ERROR_PASSWORD',
70 | message: '密码错误',
71 | }
72 | return
73 | } else {
74 | ctx.session.user_id = user.user_id;
75 | const userinfo = await ctx.model.UserInfo.findOne({ user_id: user.user_id }, '-_id');
76 | ctx.body = userinfo
77 | }
78 | } catch (err) {
79 | console.log('用户登陆失败', err);
80 | ctx.body = {
81 | status: 0,
82 | type: 'SAVE_USER_FAILED',
83 | message: '登陆失败',
84 | }
85 | }
86 | }
87 |
88 | async getInfo() {
89 | const ctx = this.ctx
90 | const sid = ctx.session.user_id;
91 | const qid = ctx.query.user_id;
92 | const user_id = sid || qid;
93 |
94 | if (!user_id || !Number(user_id)) {
95 | console.log('获取用户信息的参数user_id无效', user_id)
96 | ctx.body = {
97 | status: 0,
98 | type: 'GET_USER_INFO_FAIELD',
99 | message: '通过session获取用户信息失败',
100 | }
101 | return
102 | }
103 |
104 | try {
105 | const userinfo = await ctx.model.UserInfo.findOne({ user_id }, '-_id');
106 | ctx.body = userinfo
107 | } catch (err) {
108 | console.log('通过session获取用户信息失败', err);
109 | ctx.body = {
110 | status: 0,
111 | type: 'GET_USER_INFO_FAIELD',
112 | message: '通过session获取用户信息失败',
113 | }
114 | }
115 | }
116 |
117 | async getInfoById() {
118 | const ctx = this.ctx
119 | const user_id = ctx.params.user_id;
120 | if (!user_id || !Number(user_id)) {
121 | console.log('通过ID获取用户信息失败')
122 | ctx.body = {
123 | status: 0,
124 | type: 'GET_USER_INFO_FAIELD',
125 | message: '通过用户ID获取用户信息失败',
126 | }
127 | return
128 | }
129 | try {
130 | const userinfo = await ctx.model.UserInfo.findOne({ user_id }, '-_id');
131 | ctx.body = userinfo
132 | } catch (err) {
133 | console.log('通过用户ID获取用户信息失败', err);
134 | ctx.body = {
135 | status: 0,
136 | type: 'GET_USER_INFO_FAIELD',
137 | message: '通过用户ID获取用户信息失败',
138 | }
139 | }
140 | }
141 |
142 | async signout() {
143 | const ctx = this.ctx
144 | delete ctx.session.user_id;
145 | ctx.body = {
146 | status: 1,
147 | message: '退出成功'
148 | }
149 | }
150 |
151 | async chanegPassword() {}
152 |
153 | async getUserList() {
154 | const ctx = this.ctx
155 | const { limit = 20, offset = 0 } = ctx.query;
156 | try {
157 | const users = await ctx.model.UserInfo.find({}, '-_id').sort({ user_id: -1 }).limit(Number(limit)).skip(Number(offset));
158 | ctx.body = users
159 | } catch (err) {
160 | console.log('获取用户列表数据失败', err);
161 | ctx.body = {
162 | status: 0,
163 | type: 'GET_DATA_ERROR',
164 | message: '获取用户列表数据失败'
165 | }
166 | }
167 | }
168 |
169 | async getUserCount() {
170 | const ctx = this.ctx
171 | try {
172 | const count = await ctx.model.UserInfo.count();
173 | ctx.body = {
174 | status: 1,
175 | count,
176 | }
177 | } catch (err) {
178 | console.log('获取用户数量失败', err);
179 | ctx.body = {
180 | status: 0,
181 | type: 'ERROR_TO_GET_USER_COUNT',
182 | message: '获取用户数量失败'
183 | }
184 | }
185 | }
186 |
187 | async updateAvatar() {}
188 |
189 | async getUserCity() {
190 | const ctx = this.ctx
191 | const cityArr = ['北京', '上海', '深圳', '杭州'];
192 | const filterArr = [];
193 | let itemCity;
194 |
195 | cityArr.forEach(async item => {
196 | filterArr.push(await ctx.model.UserInfo.find({ city: item }).count())
197 | // itemCity = await ctx.model.UserInfo.find({ city: item }).count()
198 | // filterArr.push(itemCity)
199 | })
200 |
201 | filterArr.push(await ctx.model.UserInfo.$where('!"北京上海深圳杭州".includes(this.city)').count())
202 | // const filterItem = await ctx.model.UserInfo.$where('!"北京上海深圳杭州".includes(this.city)').count()
203 | // filterArr.push(filterItem)
204 |
205 | Promise.all(filterArr).then(result => {
206 | ctx.body = {
207 | status: 1,
208 | user_city: {
209 | beijing: result[0],
210 | shanghai: result[1],
211 | shenzhen: result[2],
212 | hangzhou: result[3],
213 | qita: result[4],
214 | }
215 | }
216 | }).catch(err => {
217 | console.log('获取用户分布城市数据失败', err);
218 | ctx.body = {
219 | status: 0,
220 | type: 'ERROR_GET_USER_CITY',
221 | message: '获取用户分布城市数据失败'
222 | }
223 | })
224 | }
225 |
226 | encryption(password) {
227 | const newpassword = this.Md5(this.Md5(password).substr(2, 7) + this.Md5(password));
228 | return newpassword
229 | }
230 | Md5(password) {
231 | const md5 = crypto.createHash('md5');
232 | return md5.update(password).digest('base64');
233 | }
234 | }
235 |
236 | module.exports = UserService
--------------------------------------------------------------------------------
/app/service/v3/explain.js:
--------------------------------------------------------------------------------
1 | const Service = require('egg').Service
2 |
3 | class ExplainService extends Service {
4 | async getExpalin() {
5 | const ctx = this.ctx
6 | try {
7 | const explain = await ctx.model.Explain.findOne();
8 | ctx.body = explain.data
9 | } catch (err) {
10 | console.log('获取服务中心数据失败', err);
11 | ctx.body = {
12 | status: 0,
13 | type: 'ERROR_GET_SERVER_DATA',
14 | message: '获取服务中心数据失败'
15 | }
16 | }
17 | }
18 | }
19 |
20 | module.exports = ExplainService
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | environment:
2 | matrix:
3 | - nodejs_version: '8'
4 |
5 | install:
6 | - ps: Install-Product node $env:nodejs_version
7 | - npm i npminstall && node_modules\.bin\npminstall
8 |
9 | test_script:
10 | - node --version
11 | - npm --version
12 | - npm run test
13 |
14 | build: off
15 |
--------------------------------------------------------------------------------
/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = appInfo => {
4 | const config = exports = {};
5 |
6 | // use for cookie sign key, should change to your own and keep security
7 | config.keys = appInfo.name + '_1513831973207_6454';
8 |
9 | // add your config here
10 | config.middleware = [];
11 |
12 | config.mongoose = {
13 | url: 'mongodb://127.0.0.1/eggadmin',
14 | options: {
15 | // auth: { "authSource": "admin" },
16 | // user: "root",
17 | // pass: "root",
18 | }
19 | }
20 |
21 | // session设置
22 | config.session = {
23 | renew: true,
24 | };
25 |
26 | config.security = {
27 | csrf: {
28 | enable: false,
29 | }
30 | }
31 |
32 | config.cors = {
33 | origin: 'http://47.110.44.176',
34 | allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH',
35 | credentials: true
36 | }
37 |
38 | config.multipart = {
39 | mode: 'file',
40 | };
41 |
42 | config.static = {
43 |
44 | };
45 |
46 | config.alinode = {
47 | appid: '76897',
48 | secret: 'b132d850c600c635c20f45d39fca78c3b1a2a30f',
49 | };
50 |
51 | return config;
52 | };
--------------------------------------------------------------------------------
/config/plugin.js:
--------------------------------------------------------------------------------
1 | // had enabled by egg
2 | // exports.static = true;
3 |
4 | exports.validate = {
5 | enable: true,
6 | package: 'egg-validate',
7 | }
8 |
9 | exports.mongoose = {
10 | enable: true,
11 | package: 'egg-mongoose',
12 | }
13 |
14 | exports.cors = {
15 | enable: true,
16 | package: 'egg-cors',
17 | }
18 |
19 | exports.alinode = {
20 | enable: true,
21 | package: 'egg-alinode'
22 | };
--------------------------------------------------------------------------------
/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -ev
3 |
4 | # 登陆远程主机
5 | sshpass -e ssh -o stricthostkeychecking=no root@47.91.253.116
6 |
7 | # 拉取最新代码
8 | cd /var/api/bxg-api
9 | git pull
10 |
11 | # 停止服务器
12 | npm stop
13 |
14 | # 重新启动服务器
15 | npm start
16 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bxg-api",
3 | "version": "1.0.0",
4 | "description": "",
5 | "private": true,
6 | "dependencies": {
7 | "blueimp-md5": "^2.10.0",
8 | "captchapng": "^0.0.1",
9 | "egg": "^2.0.0",
10 | "egg-alinode": "^2.0.1",
11 | "egg-cors": "^2.0.0",
12 | "egg-mongoose": "^2.1.1",
13 | "egg-scripts": "^2.1.0",
14 | "egg-static": "^2.1.1",
15 | "egg-validate": "^1.0.0",
16 | "egg-view-assets": "^1.3.0",
17 | "formidable": "^1.2.1",
18 | "gm": "^1.23.1",
19 | "jwt-simple": "^0.5.1",
20 | "moment": "^2.22.2",
21 | "pinyin": "^2.8.3"
22 | },
23 | "devDependencies": {
24 | "autod": "^3.0.1",
25 | "autod-egg": "^1.0.0",
26 | "egg-bin": "^4.3.5",
27 | "egg-ci": "^1.8.0",
28 | "egg-mock": "^3.13.0",
29 | "eslint": "^4.11.0",
30 | "eslint-config-egg": "^5.1.0",
31 | "webstorm-disable-index": "^1.2.0"
32 | },
33 | "engines": {
34 | "node": ">=8.9.0"
35 | },
36 | "scripts": {
37 | "start": "egg-scripts start --daemon",
38 | "stop": "egg-scripts stop",
39 | "dev": "egg-bin dev",
40 | "debug": "egg-bin debug",
41 | "test": "npm run lint -- --fix && npm run test-local",
42 | "test-local": "egg-bin test",
43 | "cov": "egg-bin cov",
44 | "lint": "eslint .",
45 | "ci": "npm run lint && npm run cov",
46 | "autod": "autod"
47 | },
48 | "ci": {
49 | "version": "8"
50 | },
51 | "repository": {
52 | "type": "git",
53 | "url": ""
54 | },
55 | "author": "lipengzhou",
56 | "license": "MIT"
57 | }
58 |
--------------------------------------------------------------------------------
/server.md:
--------------------------------------------------------------------------------
1 | # 服务器部署前端&node 项目(包括阿里云服务器、nginx 以及 mongoDB 的配置)
2 |
3 | > 建议不熟悉 linux 命令的小伙伴同时打开我的另一篇博客[linux 常用操作](https://www.jianshu.com/p/0c6242c61c16)
4 |
5 | ## 服务器购买&配置
6 |
7 | 1. 打开阿里云,选择购买云服务器 ECS,这里可以选择[一键购买](https://ecs-buy.aliyun.com/simple/#/simple)进行快速配置,操作系统选择 CentOS 7.2 64 位,其他默认或根据实际需求来,若选择自定义购买请自行搜索;
8 | 2. 购买成功设置账号密码后,就可以通过 ftp 工具(我用的是 FileZilla)或者 git 连接我们的服务器了,这个时候我们也可以打开阿里云的控制台/云服务器 ECS 查看购买的服务器;
9 | 3. 打开阿里云的控制台/云服务器 ECS/网络和安全/安全组,在安全组列表点击配置规则,点击快速创建规则,就可以暴露端口了。比如暴露 80 端口,选择 HTTP(80),授权对象填`0.0.0.0/0`,其他默认就可以了。暴露其他端口你就在自定义端口选择,比如暴露 7001 端口,你就在自定义端口选择 TCP,输入`7001/7001`即可。
10 | 4. 开启[node 性能平台](https://node.console.aliyun.com/#!/owned),点击创建新应用按照操作提示来就行,成功开启后在项目配置(具体配置看下文))就可以监控数据了。
11 |
12 | ## 连接服务器
13 |
14 | 1. git 连接
15 |
16 | ```
17 | # ssh remote_username@remote_ip 然后输入密码即可
18 |
19 | 如果ssh不存在,执行以下命令即可
20 | # yum install openssh-client 下载客户端ssh
21 | ```
22 |
23 | 2. ftp 工具连接(这里以 FileZilla 为例),下载 filezilla 后,点击新建站点,输入主机 ip,选择 sftp 协议,选择登录类型为正常,输入账号密码即可
24 |
25 | ## 部署 node 环境
26 |
27 | 1. 部署 node 环境
28 |
29 | ```
30 | # ssh remote_username@remote_ip 连接服务器
31 | # wget https://nodejs.org/dist/v6.9.5/node-v6.9.5-linux-x64.tar.xz 下载node压缩文件
32 | # tar xvf node-v6.9.5-linux-x64.tar.xz 解压
33 | # ln -s /root/node-v6.9.5-linux-x64/bin/node /usr/local/bin/node 创建软连接
34 | # ln -s /root/node-v6.9.5-linux-x64/bin/npm /usr/local/bin/npm 创建软连接
35 | # node -v 查看node版本
36 | # npm -v 查看npm版本
37 | ```
38 |
39 | 2. 其他
40 |
41 | ```
42 | # yum install vim 下载vim
43 | ```
44 |
45 | ## nginx 安装&配置
46 |
47 | 1. nginx 安装
48 |
49 | ```
50 | # yum install epel-release 下载epel-release
51 | # yun install nginx 下载nginx
52 | # cd /etc/nginx
53 | # vim nginx.conf 用vim打开nginx.conf
54 | ```
55 |
56 | 2. 修改 nginx.conf
57 |
58 | - 修改 user 为 root
59 | - 修改 server 如下,这里 wx 是指向代理另一个 node 微信公众号项目(运行在 7002 端口,但微信公众号配置 http 只允许 80 端口,所以设置代理,我们的 elm 接口运行在 7001 不用代理)
60 |
61 | ```
62 | server {
63 | listen 80 default_server;
64 | listen [::]:80 default_server;
65 | server_name _;
66 | root /root/www/;
67 |
68 | include /etc/nginx/default.d/*.conf;
69 |
70 | location /wx/ {
71 | proxy_pass http://127.0.0.1:7002/;
72 | }
73 |
74 | error_page 404 /404.html;
75 | location = /40x.html {
76 | }
77 |
78 | error_page 500 502 503 504 /50x.html;
79 | location = /50x.html {
80 | }
81 | }
82 | ```
83 |
84 | 3. 启动 nginx
85 |
86 | ```
87 | nginx -t 测试nginx语法是否有误
88 | nginx 启动nginx
89 | nginx -s reload 重启nginx,修改nginx.conf后记得重启
90 | ```
91 |
92 | 4. 其他命令
93 |
94 | ```
95 | ps -ef | grep nginx 显示nginx进程
96 | nginx -s stop 停止nginx
97 | nginx -v 查看nginx版本
98 | ```
99 |
100 | ## 部署 mongodb
101 |
102 | 1. 安装 mongodb
103 |
104 | ```
105 | # ssh remote_username@remote_ip 连接服务器
106 | # curl -O https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.0.6.tgz 下载
107 | # tar -zxvf mongodb-linux-x86_64-3.0.6.tgz 解压
108 | # mkdir data 创建数据库文件夹
109 | # touch mongodb.log 创建日志文件
110 | # cd /usr/local/mongodb/bin
111 | # ./mongod -dbpath=/usr/local/mongodb/data -logpath=/usr/local/mongodb/mongodb.log -logappend -port=27017 -fork 注意fork是后台启动,避免又要再开窗口重新连接服务器再能进行其他操作
112 | # ./mongo 连接mongodb
113 | ```
114 |
115 | 2. 配置随 linux 启动
116 | 在/etc/rc.local 添加如下即可:
117 |
118 | ```
119 | # rm /usr/local/mongodb/data/mongod.lock 停止可能在运行的mongo
120 | # /.../bin/mongod -dbpath /usr/local/mongodb/data -logpath /usr/local/mongodb/mongodb.log -logappend -fork -port 27017
121 | ```
122 |
123 | 3. 设置权限
124 |
125 | ```
126 | # cd /usr/local/mongodb/bin
127 | # ./mongod -dbpath=/usr/local/mongodb/data -logpath=/usr/local/mongodb/mongodb.log -logappend -port=27017 -fork
128 | # ./mongo
129 | > use admin
130 | > db.createUser(
131 | > {
132 | > user: "root",
133 | > pwd: "123456",
134 | > roles: [ { role: "root", db: "admin" } ]
135 | > }
136 | > )
137 | > db.shutdownServer();
138 | # ./mongod -dbpath=/usr/local/mongodb/data -logpath=/usr/local/mongodb/mongodb.log -logappend -port=27017 -fork --auth
139 | # db.auth("root","123456")
140 | ```
141 |
142 | 4. 项目中连接 mongodb(这里以 koa 框架 egg 项目为例,其他 node 请自行查找)
143 |
144 | ```
145 | # cnpm i egg-mongoose -S
146 |
147 | // config/plugin.js
148 | exports.mongoose = {
149 | enable: true,
150 | package: 'egg-mongoose',
151 | }
152 |
153 | // config/config.default.js
154 | config.mongoose = {
155 | url: 'mongodb://127.0.0.1/eggadmin',
156 | options: {
157 | // 如果设置了密码
158 | // auth: { "authSource": "admin" },
159 | // user: "root",
160 | // pass: "123456",
161 | }
162 | }
163 | ```
164 |
165 | ## 部署 node 项目
166 |
167 | > 部署环境 阿里云 CentOS 7.2 64 位
168 |
169 | 1. 本地项目根目录(删除 node_modules,建议依赖在服务器下载)
170 |
171 | ```
172 | # tar -zcvf ../file_name.tgz . 打包
173 | # scp ../file_name.tgz remote_username@remote_ip:/root/www/server 上传到服务器
174 | ```
175 |
176 | 2. 服务器
177 |
178 | ```
179 | # ssh remote_username@remote_ip 连接服务器
180 | # cd /root/www
181 | # mkdir server 这里创建server文件夹放node项目代码
182 | # cd server
183 | # tar -zxvf file_name.tgz . 解压
184 | # cnpm install --production 安装生产环境依赖
185 |
186 | 1. koa项目(express项目类似)
187 | # cnpm i -g pm2 下载pm2
188 | # pm2 start bin/www 守护进程启动
189 | # pm2 restart app_name|app_id 重启
190 | # pm2 stop app_name|app_id 停止
191 | # pm2 list 查看进程状态
192 | # pm2 stop all 停止所有应用
193 | # pm2 start ./bin/www --watch 监听更改自动重启
194 |
195 | 2. egg项目
196 | # npm start 运行
197 | # npm stop 停止
198 |
199 | ```
200 |
201 | 3. 阿里 node 性能平台监控
202 |
203 | 1.koa 项目(express 项目类似)
204 |
205 | ```
206 | # wget -O- https://raw.githubusercontent.com/aliyun-node/tnvm/master/install.sh | bash 安装版本管理工具 tnvm
207 | # source ~/.bashrc
208 | # tnvm ls-remote alinode 查看需要的版本
209 | # tnvm install alinode-v3.11.4 安装需要的版本
210 | # tnvm use alinode-v3.11. 使用需要的版本
211 | ```
212 |
213 | 新建 config.json 文件如下,从[node 性能平台](https://node.console.aliyun.com/#!/owned)获取对应的接入参数
214 |
215 | ```
216 | {
217 | "appid": "",
218 | "secret": ""
219 | }
220 | ```
221 |
222 | ```
223 | # cnpm install @alicloud/agenthub -g 安装 agenthub
224 | # agenthub start config.json 启动agenthub
225 | # agenthub list 查看 agenthub 列表
226 | # ENABLE_NODE_LOG=YES pm2 start bin/www 使用pm2管理的应用
227 | ```
228 |
229 | 2.egg 项目
230 |
231 | ```
232 | # cnpm i nodeinstall -g
233 | # nodeinstall --install-alinode ^3
234 | # cnpm i egg-alinode --save
235 | # npm start
236 | ```
237 |
238 | ```
239 | // config/plugin.js
240 | exports.alinode = {
241 | enable: true,
242 | package: 'egg-alinode',
243 | };
244 |
245 | // config/config.default.js
246 | config.alinode = {
247 | appid: '',
248 | secret: '',
249 | };
250 | ```
251 |
252 | ## 部署前端项目(这里以 vue 为例)
253 |
254 | 1. 修改前端项目打包配置:注意我们要修改打包后路径,不然会取不到 js 等资源
255 |
256 | 1. 基于 webpack 打包的项目(以 app 项目为例)
257 |
258 | ```
259 | // config/index.js
260 | // build
261 | assetsPublicPath: '/app/'
262 | ```
263 |
264 | 2. uniapp 打包的项目
265 |
266 | ```
267 | // manifest.json
268 | "h5":{
269 | "router":{
270 | "base":"/app/"
271 | }
272 | },
273 | ```
274 |
275 | 2. 打包
276 | 在项目根目录`npm run build`,然后把 dist 文件夹里的内容传到服务器,这里我们把两个项目分部传到/root/www/app 和/root/www/admin,记得提前创建 app 和 admin 文件夹
277 |
278 | ## 项目实战
279 |
280 | [全栈项目-基于 koa 框架 egg 的服务端接口](https://github.com/majun00/egg-api) 求一个 star~
281 |
282 | > 本人水平有限,欢迎大家交流指正。本文为作者原创,转载请注明出处。
283 |
--------------------------------------------------------------------------------
/test/app/controller/home.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { app, assert } = require('egg-mock/bootstrap');
4 |
5 | describe('test/app/controller/home.test.js', () => {
6 |
7 | it('should assert', function* () {
8 | const pkg = require('../../../package.json');
9 | assert(app.config.keys.startsWith(pkg.name));
10 |
11 | // const ctx = app.mockContext({});
12 | // yield ctx.service.xx();
13 | });
14 |
15 | it('should GET /', () => {
16 | return app.httpRequest()
17 | .get('/')
18 | .expect('hi, egg')
19 | .expect(200);
20 | });
21 | });
22 |
--------------------------------------------------------------------------------