├── static
├── .gitkeep
└── css
│ └── reset.css
├── .eslintignore
├── src
├── store
│ ├── getters.js
│ ├── actions.js
│ ├── mutation-types.js
│ ├── index.js
│ └── modules
│ │ ├── user.js
│ │ ├── msite.js
│ │ └── shop.js
├── common
│ ├── imgs
│ │ └── loading.gif
│ └── stylus
│ │ └── mixins.styl
├── pages
│ ├── Order
│ │ ├── images
│ │ │ └── person.png
│ │ └── Order.vue
│ ├── test
│ │ ├── B2.vue
│ │ ├── A.vue
│ │ ├── B1.vue
│ │ └── B.vue
│ ├── NotFound
│ │ └── NotFound.vue
│ ├── Search
│ │ └── Search.vue
│ ├── Shop
│ │ ├── Shop.vue
│ │ ├── ShopInfo
│ │ │ └── ShopInfo.vue
│ │ ├── ShopGoods
│ │ │ └── ShopGoods.vue
│ │ └── ShopRatings
│ │ │ └── ShopRatings.vue
│ ├── MSite
│ │ ├── images
│ │ │ └── msite_back.svg
│ │ └── MSite.vue
│ ├── Profile
│ │ └── Profile.vue
│ └── Login
│ │ ├── images
│ │ └── captcha.svg
│ │ └── Login.vue
├── components
│ ├── Star
│ │ ├── images
│ │ │ ├── star24_half@2x.png
│ │ │ ├── star24_half@3x.png
│ │ │ ├── star24_off@2x.png
│ │ │ ├── star24_off@3x.png
│ │ │ ├── star24_on@2x.png
│ │ │ ├── star24_on@3x.png
│ │ │ ├── star36_half@2x.png
│ │ │ ├── star36_half@3x.png
│ │ │ ├── star36_off@2x.png
│ │ │ ├── star36_off@3x.png
│ │ │ ├── star36_on@2x.png
│ │ │ ├── star36_on@3x.png
│ │ │ ├── star48_half@2x.png
│ │ │ ├── star48_half@3x.png
│ │ │ ├── star48_off@2x.png
│ │ │ ├── star48_off@3x.png
│ │ │ ├── star48_on@2x.png
│ │ │ └── star48_on@3x.png
│ │ └── Star.vue
│ ├── Split
│ │ └── Split.vue
│ ├── ShopList
│ │ ├── images
│ │ │ └── shop_back.svg
│ │ └── ShopList.vue
│ ├── NavHeader
│ │ └── NavHeader.vue
│ ├── CartControl
│ │ └── CartControl.vue
│ ├── FooterGuide
│ │ └── FooterGuide.vue
│ ├── RatingsFilter
│ │ └── RatingsFilter.vue
│ ├── Food
│ │ └── Food.vue
│ ├── ShopCart
│ │ └── ShopCart.vue
│ └── ShopHeader
│ │ └── ShopHeader.vue
├── filters
│ └── index.js
├── mock
│ └── mockServer.js
├── App.vue
├── router
│ ├── index.js
│ └── routes.js
├── main.js
└── api
│ ├── ajax.js
│ └── index.js
├── config
├── prod.env.js
├── dev.env.js
└── index.js
├── .editorconfig
├── .gitignore
├── .postcssrc.js
├── .babelrc
├── .eslintrc.js
├── index.html
├── 导航卫士.md
├── package.json
├── README.md
└── API文档.md
/static/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | /build/
2 | /config/
3 | /dist/
4 | /*.js
5 | *.vue
6 | *.js
--------------------------------------------------------------------------------
/src/store/getters.js:
--------------------------------------------------------------------------------
1 | /*
2 | 包含n个getter计算属性方法的对象
3 | */
4 | export default {
5 |
6 | }
--------------------------------------------------------------------------------
/src/store/actions.js:
--------------------------------------------------------------------------------
1 | /*
2 | 包含n个用于间接更新状态数据的方法的对象
3 | */
4 |
5 | export default {
6 |
7 | }
--------------------------------------------------------------------------------
/config/prod.env.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | module.exports = {
3 | NODE_ENV: '"production"'
4 | }
5 |
--------------------------------------------------------------------------------
/src/common/imgs/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxfjd3g/180810_gshop-client/HEAD/src/common/imgs/loading.gif
--------------------------------------------------------------------------------
/src/pages/Order/images/person.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxfjd3g/180810_gshop-client/HEAD/src/pages/Order/images/person.png
--------------------------------------------------------------------------------
/src/components/Star/images/star24_half@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxfjd3g/180810_gshop-client/HEAD/src/components/Star/images/star24_half@2x.png
--------------------------------------------------------------------------------
/src/components/Star/images/star24_half@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxfjd3g/180810_gshop-client/HEAD/src/components/Star/images/star24_half@3x.png
--------------------------------------------------------------------------------
/src/components/Star/images/star24_off@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxfjd3g/180810_gshop-client/HEAD/src/components/Star/images/star24_off@2x.png
--------------------------------------------------------------------------------
/src/components/Star/images/star24_off@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxfjd3g/180810_gshop-client/HEAD/src/components/Star/images/star24_off@3x.png
--------------------------------------------------------------------------------
/src/components/Star/images/star24_on@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxfjd3g/180810_gshop-client/HEAD/src/components/Star/images/star24_on@2x.png
--------------------------------------------------------------------------------
/src/components/Star/images/star24_on@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxfjd3g/180810_gshop-client/HEAD/src/components/Star/images/star24_on@3x.png
--------------------------------------------------------------------------------
/src/components/Star/images/star36_half@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxfjd3g/180810_gshop-client/HEAD/src/components/Star/images/star36_half@2x.png
--------------------------------------------------------------------------------
/src/components/Star/images/star36_half@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxfjd3g/180810_gshop-client/HEAD/src/components/Star/images/star36_half@3x.png
--------------------------------------------------------------------------------
/src/components/Star/images/star36_off@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxfjd3g/180810_gshop-client/HEAD/src/components/Star/images/star36_off@2x.png
--------------------------------------------------------------------------------
/src/components/Star/images/star36_off@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxfjd3g/180810_gshop-client/HEAD/src/components/Star/images/star36_off@3x.png
--------------------------------------------------------------------------------
/src/components/Star/images/star36_on@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxfjd3g/180810_gshop-client/HEAD/src/components/Star/images/star36_on@2x.png
--------------------------------------------------------------------------------
/src/components/Star/images/star36_on@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxfjd3g/180810_gshop-client/HEAD/src/components/Star/images/star36_on@3x.png
--------------------------------------------------------------------------------
/src/components/Star/images/star48_half@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxfjd3g/180810_gshop-client/HEAD/src/components/Star/images/star48_half@2x.png
--------------------------------------------------------------------------------
/src/components/Star/images/star48_half@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxfjd3g/180810_gshop-client/HEAD/src/components/Star/images/star48_half@3x.png
--------------------------------------------------------------------------------
/src/components/Star/images/star48_off@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxfjd3g/180810_gshop-client/HEAD/src/components/Star/images/star48_off@2x.png
--------------------------------------------------------------------------------
/src/components/Star/images/star48_off@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxfjd3g/180810_gshop-client/HEAD/src/components/Star/images/star48_off@3x.png
--------------------------------------------------------------------------------
/src/components/Star/images/star48_on@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxfjd3g/180810_gshop-client/HEAD/src/components/Star/images/star48_on@2x.png
--------------------------------------------------------------------------------
/src/components/Star/images/star48_on@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxfjd3g/180810_gshop-client/HEAD/src/components/Star/images/star48_on@3x.png
--------------------------------------------------------------------------------
/config/dev.env.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const merge = require('webpack-merge')
3 | const prodEnv = require('./prod.env')
4 |
5 | module.exports = merge(prodEnv, {
6 | NODE_ENV: '"development"'
7 | })
8 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | /dist/
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Editor directories and files
9 | .idea
10 | .vscode
11 | *.suo
12 | *.ntvs*
13 | *.njsproj
14 | *.sln
15 |
--------------------------------------------------------------------------------
/src/filters/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | 用来自定义过滤器的模块
3 | */
4 | import Vue from 'vue'
5 | import moment from 'moment'
6 |
7 | // 日期格式化
8 | Vue.filter('date-format', (value, format) => {
9 | return moment(value).format(format || 'YYYY-MM-DD HH:mm:ss')
10 | })
11 |
--------------------------------------------------------------------------------
/src/pages/test/B2.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | B2组件
4 |
5 |
6 |
13 |
--------------------------------------------------------------------------------
/src/pages/test/A.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
AAAAA组件---必须登陆
4 |
5 |
6 |
13 |
--------------------------------------------------------------------------------
/.postcssrc.js:
--------------------------------------------------------------------------------
1 | // https://github.com/michael-ciniawsky/postcss-load-config
2 |
3 | module.exports = {
4 | "plugins": {
5 | "postcss-import": {},
6 | "postcss-url": {},
7 | // to edit target browsers: use "browserslist" field in package.json
8 | "autoprefixer": {}
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/pages/NotFound/NotFound.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
找不到对应页面
4 |
5 |
6 |
7 |
8 |
13 |
14 |
17 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["env", {
4 | "modules": false,
5 | "targets": {
6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
7 | }
8 | }],
9 | "stage-2"
10 | ],
11 | "plugins": ["transform-vue-jsx","transform-runtime",["component", [
12 | {
13 | "libraryName": "mint-ui",
14 | "style": true
15 | }
16 | ]]]
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/src/mock/mockServer.js:
--------------------------------------------------------------------------------
1 | /*
2 | 使用mockjs提供mock数据接口
3 | */
4 | import Mock from 'mockjs'
5 | import data from './data.json' // 已自动解析js对应的类型: 对象
6 |
7 | // goods的接口
8 | Mock.mock('/goods', {code: 0, data: data.goods})
9 | // ratings的接口
10 | Mock.mock('/ratings', {code: 0, data: data.ratings})
11 | // info的接口
12 | Mock.mock('/info', {code: 0, data: data.info})
13 |
14 | console.log('mockServer....')
15 |
16 | // export 不需要向外暴露任何东西
--------------------------------------------------------------------------------
/src/components/Split/Split.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
19 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
24 |
25 |
28 |
--------------------------------------------------------------------------------
/src/store/mutation-types.js:
--------------------------------------------------------------------------------
1 | /*
2 | 包含n个mutation函数常量名称的模块
3 | 有几个type就需要定义几个mutation函数
4 | */
5 | export const RECEIVE_ADDRESS = 'receive_address' // 接收地址信息
6 | export const RECEIVE_CATEGORYS = 'receive_categorys' // 接收分类数组
7 | export const RECEIVE_SHOPS = 'receive_shops' // 接收商家数组
8 | export const RECEIVE_USER = 'receive_user' // 接收用户信息
9 | export const RESET_USER = 'reset_user' // 重置用户信息
10 | export const RECEIVE_GOODS = 'receive_goods' // 接收商品数组
11 | export const RECEIVE_RATINGS = 'receive_ratings' // 接收商家评价数组
12 | export const RECEIVE_INFO = 'receive_info' // 接收商家信息
13 | export const ADD_FOOD_COUNT = 'add_food_count' // 增加food的数量
14 | export const REDUCE_FOOD_COUNT = 'reduce_food_count' // 减少food的数量
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | 路由器对象模块
3 | */
4 | import Vue from 'vue'
5 | import VueRouter from 'vue-router'
6 |
7 | import routes from './routes'
8 |
9 | Vue.use(VueRouter)
10 |
11 | const router = new VueRouter({
12 | mode: 'history', // 去除路由路径中的#
13 | routes
14 | })
15 |
16 | // 所有需要检查是否登陆的path的数组
17 | const paths = ['/a', '/b']
18 |
19 | // 添加全局前置守卫
20 | router.beforeEach((to, from, next) => {
21 | console.log('beforeEach', to, from)
22 | // 得到请求的路由路径
23 | const path = to.path
24 | // 如果在需要检查的paths中
25 | if(paths.indexOf(path)>=0) {
26 | // 判断是否已经登陆
27 | const userId = Vue.store.state.user.user._id
28 | // 如果已登陆, 放行
29 | if(userId) {
30 | next()
31 | } else {// 如果没有, 直接跳转到登陆
32 | next('/login')
33 | }
34 | } else { // 如果不在, 直接放行
35 | // 放行
36 | next()
37 | }
38 |
39 | })
40 |
41 |
42 | export default router
--------------------------------------------------------------------------------
/src/pages/test/B1.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | B11111组件
4 |
5 |
6 |
38 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // https://eslint.org/docs/user-guide/configuring
2 |
3 | module.exports = {
4 | root: true,
5 | parserOptions: {
6 | parser: 'babel-eslint'
7 | },
8 | env: {
9 | browser: true,
10 | },
11 | extends: [
12 | // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
13 | // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
14 | 'plugin:vue/essential',
15 | // https://github.com/standard/standard/blob/master/docs/RULES-en.md
16 | 'standard'
17 | ],
18 | // required to lint *.vue files
19 | plugins: [
20 | 'vue'
21 | ],
22 | // add your custom rules here
23 | rules: {
24 | // allow async-await
25 | 'generator-star-spacing': 'off',
26 | // allow debugger during development
27 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | vuex最核心的管理对象模块
3 | */
4 | import Vue from 'vue'
5 | import Vuex from 'vuex'
6 |
7 | import actions from './actions'
8 | import getters from './getters'
9 | import msite from './modules/msite'
10 | import user from './modules/user'
11 | import shop from './modules/shop'
12 |
13 | Vue.use(Vuex)
14 |
15 | export default new Vuex.Store({ // options
16 | modules: {
17 | msite,
18 | user,
19 | shop
20 | },
21 | // state,
22 | actions,
23 | getters,
24 | })
25 |
26 | /*
27 |
28 | store.state = {
29 | msite: options.modules.msite.state,
30 | user: options.modules.user.state,
31 | }
32 | */
33 |
34 | /*
35 | vuex管理的state的结构:
36 | {
37 | msite: {
38 | latitude: 40.10038, // 纬度
39 | longitude: 116.36867, // 经度
40 | address: {}, // 地址信息对象
41 | categorys: [], // 食品分类数组
42 | shops: [], // 商家数组
43 | },
44 | user: {
45 | user: {}, // 登陆的用户信息
46 | }
47 | }
48 | */
--------------------------------------------------------------------------------
/src/pages/Order/Order.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 登录后查看外卖订单
7 |
8 |
9 |
10 |
11 |
12 |
15 |
16 |
--------------------------------------------------------------------------------
/src/components/ShopList/images/shop_back.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import {Button} from 'mint-ui'
3 | import VueLazyload from 'vue-lazyload'
4 |
5 | import App from './App.vue'
6 | import router from './router'
7 | import store from './store'
8 |
9 | import NavHeader from './components/NavHeader/NavHeader.vue'
10 | import Star from './components/Star/Star.vue'
11 | import CartControl from './components/CartControl/CartControl.vue'
12 | import Split from './components/Split/Split.vue'
13 |
14 | import loading from './common/imgs/loading.gif'
15 | import './mock/mockServer'
16 | import './filters'
17 |
18 | Vue.use(VueLazyload, {
19 | loading
20 | }) // 内部定义了一个全局指令: lazy
21 |
22 |
23 | // 注册全局组件
24 | Vue.component('NavHeader', NavHeader)
25 | Vue.component('Star', Star)
26 | Vue.component('CartControl', CartControl)
27 | Vue.component('Split', Split)
28 | Vue.component(Button.name, Button)
29 |
30 | // 将store保存到Vue函数对象上
31 | Vue.store = store
32 |
33 | /* eslint-disable no-new */
34 | new Vue({
35 | el: '#app',
36 | render: h => h(App),
37 | router,
38 | store
39 | })
40 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
7 | gshop
8 |
9 |
10 |
11 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/store/modules/user.js:
--------------------------------------------------------------------------------
1 | /*
2 | 管理用户相关状态数据
3 | */
4 | import {reqLogout, reqUserInfo} from '../../api'
5 | import {
6 | RECEIVE_USER,
7 | RESET_USER
8 | } from '../mutation-types'
9 |
10 | const state = {
11 | user: {}, // 登陆的用户信息
12 | }
13 | const mutations = {
14 | [RECEIVE_USER](state, {user}) {
15 | state.user = user
16 | },
17 | [RESET_USER](state) {
18 | state.user = {}
19 | },
20 | }
21 | const actions = {
22 | // 同步保存user信息
23 | saveUser({commit}, user) {
24 | commit(RECEIVE_USER, {user})
25 | },
26 |
27 | // 异步获取当前用户信息
28 | async getUser({commit}) {
29 | const result = await reqUserInfo()
30 | if (result.code === 0) {
31 | const user = result.data
32 | // 提交mutation
33 | commit(RECEIVE_USER, {user})
34 | }
35 | },
36 |
37 | // 异步退出登陆
38 | async logout({commit}) {
39 | const result = await reqLogout()
40 | if (result.code === 0) {
41 | commit(RESET_USER)
42 | }
43 | },
44 | }
45 | const getters = {}
46 |
47 | export default {
48 | state,
49 | mutations,
50 | actions,
51 | getters
52 | }
53 |
--------------------------------------------------------------------------------
/src/api/ajax.js:
--------------------------------------------------------------------------------
1 | /*
2 | 能发送ajax请求的函数模块
3 | 包装axios
4 | 函数的返回值是promise对象
5 | axios.get()/post()返回的就是promise对象
6 | */
7 | import axios from 'axios'
8 |
9 | export default function ajax(url, data={}, method='GET') {
10 |
11 | return new Promise(function (resolve, reject) {
12 | let promise
13 | // 执行异步ajax请求
14 | if(method==='GET') {
15 | promise = axios.get(url, {params: data}) // params配置指定的是query参数
16 | } else {
17 | promise = axios.post(url, data)
18 | }
19 | promise.then(response => {
20 | // 如果成功了, 调用resolve(response.data)
21 | resolve(response.data)
22 | }).catch(error => { // 对所有ajax请求出错做统一处理, 外层就不用再处理错误了
23 | // 如果失败了, 提示请求后台出错
24 | alert('请求错误: '+error.message)
25 | })
26 | })
27 | }
28 |
29 | /*
30 | const promise = ajax('/xxx')
31 | promise.then(response => {
32 | const result = response.data
33 |
34 | }).catch()
35 |
36 |
37 |
38 | */
39 | /*async function getAddress() {
40 | /!*
41 | const response = await ajax('/address')
42 | const result = response.data
43 | *!/
44 | const result = await ajax('/address')
45 | if(result.code===0) {
46 |
47 | } else {
48 |
49 | }
50 | }*/
51 |
--------------------------------------------------------------------------------
/src/common/stylus/mixins.styl:
--------------------------------------------------------------------------------
1 | $green = #02a774;
2 | $yellow = #F5A100;
3 | $bc = #e4e4e4;
4 |
5 | // 一像素下边框
6 | bottom-border-1px($color)
7 | position relative
8 | border none
9 | &:after
10 | content ''
11 | position absolute
12 | left 0
13 | bottom 0
14 | width 100%
15 | height 1px
16 | background-color $color
17 | transform scaleY(0.5)
18 |
19 | // 一像素上边框
20 | top-border-1px($color)
21 | position relative
22 | &::before
23 | content ''
24 | position absolute
25 | z-index 200
26 | left 0
27 | top 0
28 | width 100%
29 | height 1px
30 | background-color $color
31 |
32 | //根据像素比缩放1px像素边框
33 | @media only screen and (-webkit-device-pixel-ratio: 2 )
34 | .border-1px
35 | &::before
36 | transform scaleY(.5)
37 |
38 | @media only screen and (-webkit-device-pixel-ratio: 3 )
39 | .border-1px
40 | &::before
41 | transform scaleY(.333333)
42 |
43 | //根据像素比来使用 2x图 3x图
44 | bg-image($url)
45 | background-image: url($url + "@2x.png")
46 | @media (-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio: 3)
47 | background-image: url($url + "@3x.png")
48 |
49 | //清除浮动
50 | clearFix()
51 | *zoom 1
52 | &::after
53 | content ''
54 | display block
55 | clear both
--------------------------------------------------------------------------------
/src/pages/Search/Search.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
16 |
17 |
--------------------------------------------------------------------------------
/src/pages/test/B.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
BBBB组件---必须登陆
4 |
5 |
6 |
7 | b111
8 |
9 |
10 | b222
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
28 |
--------------------------------------------------------------------------------
/src/components/NavHeader/NavHeader.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
19 |
20 |
61 |
--------------------------------------------------------------------------------
/src/api/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | 包含n个接口请求函数的模块
3 | 每个函数返回promise
4 | */
5 | import ajax from './ajax'
6 |
7 | // const BASE = 'http://localhost:5000'
8 | const BASE = '/api' // 开发环境下需要使用代理帮我们转发请求
9 | // const BASE = '' // 生产环境打包
10 |
11 |
12 | // [1、根据经纬度获取位置详情](#1根据经纬度获取位置详情)
13 | /*export function reqAddress(longitude, latitude) {
14 | return ajax(`/position/${latitude},${longitude}`)
15 | }*/
16 | export const reqAddress = (longitude, latitude) => ajax(BASE + `/position/${latitude},${longitude}`)
17 |
18 | // [2、获取食品分类列表](#2获取食品分类列表)
19 | export const reqCategorys = () => ajax(BASE + '/index_category')
20 |
21 | // [3、根据经纬度获取商铺列表](#3根据经纬度获取商铺列表)
22 | export const reqShops = (longitude, latitude) => ajax(BASE + '/shops', {longitude, latitude})
23 |
24 | // [6、用户名密码登陆](#6用户名密码登陆)
25 | export const reqPwdLogin = ({name, pwd, captcha}) => ajax(BASE + '/login_pwd', {name, pwd, captcha}, 'POST')
26 |
27 | // [7、发送短信验证码](#7发送短信验证码)
28 | export const reqSendCode = (phone) => ajax(BASE + '/sendcode', {phone})
29 |
30 | // [8、手机号验证码登陆](#8手机号验证码登陆)
31 | export const reqSmsLogin = (phone, code) => ajax(BASE + '/login_sms', {phone, code}, 'POST')
32 |
33 | // [9、根据会话获取用户信息](#9根据会话获取用户信息)
34 | export const reqUserInfo = () => ajax(BASE + '/userinfo')
35 |
36 | // [10、用户登出](#10用户登出)
37 | export const reqLogout = () => ajax(BASE + '/logout')
38 |
39 | export const reqGoods = () => ajax('/goods')
40 | export const reqRatings = () => ajax('/ratings')
41 | export const reqInfo = () => ajax('/info')
--------------------------------------------------------------------------------
/src/pages/Shop/Shop.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | 点餐
8 |
9 |
10 | 评价
11 |
12 |
13 | 商家
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
37 |
38 |
66 |
--------------------------------------------------------------------------------
/src/components/CartControl/CartControl.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
{{food.count}}
7 |
8 |
9 |
10 |
11 |
25 |
26 |
64 |
65 |
--------------------------------------------------------------------------------
/src/store/modules/msite.js:
--------------------------------------------------------------------------------
1 | /*
2 | 管理msite相关状态数据
3 | */
4 | import {reqCategorys, reqAddress, reqShops} from '../../api'
5 | import {
6 | RECEIVE_ADDRESS,
7 | RECEIVE_CATEGORYS,
8 | RECEIVE_SHOPS,
9 | } from '../mutation-types'
10 |
11 | const state = {
12 | latitude: 40.10038, // 纬度
13 | longitude: 116.36867, // 经度
14 | address: {}, // 地址信息对象
15 | categorys: [], // 食品分类数组
16 | shops: [], // 商家数组
17 | }
18 | const mutations = {
19 | [RECEIVE_ADDRESS](state, {address}) {
20 | state.address = address
21 | },
22 | [RECEIVE_CATEGORYS](state, {categorys}) {
23 | state.categorys = categorys
24 | },
25 | [RECEIVE_SHOPS](state, {shops}) {
26 | state.shops = shops
27 | },
28 | }
29 | const actions = {
30 | // 异步获取地址信息
31 | async getAddress({commit, state}) {
32 | // 1. 发异步ajax请求
33 | const {longitude, latitude} = state
34 | const result = await reqAddress(longitude, latitude)
35 | // 2. 有了结果后, 提交mutation
36 | if (result.code === 0) {
37 | const address = result.data
38 | commit(RECEIVE_ADDRESS, {address})
39 | }
40 | },
41 |
42 | // 异步获食品分类列表
43 | async getCategorys({commit}, callback) {
44 | // 1. 发异步ajax请求
45 | const result = await reqCategorys()
46 | // 2. 有了结果后, 提交mutation
47 | if (result.code === 0) {
48 | const categorys = result.data
49 | commit(RECEIVE_CATEGORYS, {categorys})
50 | // 在提交mutation更新状态之后调用callback
51 | typeof callback === 'function' && callback()
52 | }
53 | },
54 |
55 | // 异步获取商家列表
56 | async getShops({commit, state}) {
57 | // 1. 发异步ajax请求
58 | const {longitude, latitude} = state
59 | const result = await reqShops(longitude, latitude)
60 | // 2. 有了结果后, 提交mutation
61 | if (result.code === 0) {
62 | const shops = result.data
63 | commit(RECEIVE_SHOPS, {shops})
64 | }
65 | },
66 | }
67 | const getters = {}
68 |
69 | export default {
70 | state,
71 | mutations,
72 | actions,
73 | getters
74 | }
75 |
--------------------------------------------------------------------------------
/src/pages/MSite/images/msite_back.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/FooterGuide/FooterGuide.vue:
--------------------------------------------------------------------------------
1 |
2 |
28 |
29 |
30 |
40 |
41 |
--------------------------------------------------------------------------------
/导航卫士.md:
--------------------------------------------------------------------------------
1 | # 1. 导航守卫是什么?
2 | 1). 导航守卫是vue-router提供的下面2个方面的功能
3 | a. 监视路由跳转
4 | b. 控制路由跳转
5 | 2). 应用
6 | a. 在跳转到界面前, 进行用户权限检查限制(如是否已登陆)
7 | b. 在界面离开前, 做收尾工作
8 |
9 | # 2. 导航守卫分类
10 | 1). 全局守卫: 针对任意路由跳转
11 | a. 全局前置守卫
12 | b. 全局后置守卫
13 | 2). 组件守卫: 只针对当前组件的路由跳转
14 | a. 进入
15 | b. 更新
16 | c. 离开
17 |
18 | # 3. 相关API
19 | 1). 全局前置守卫: 在准备跳转到某个路由组件之前 (在开发中用的比较多)
20 | router.beforeEach((to, from, next) => {// before enter each route component
21 |
22 | })
23 | 说明:
24 | ①. to: 目标route
25 | ②. from: 起始route
26 | ③. next: 函数
27 | next(): 执行下一个守卫回调, 如果没有跳转到目标路由
28 | next(false)/不执行: 跳转流程在当前处中断, 不会跳转到目标路由组件
29 | next(path): 跳转到指定的另一个路由
30 |
31 | 2). 全局后置守卫: 在跳转到某个路由组件之后
32 | router.afterEach((to, from) => {
33 |
34 | })
35 | 3). 组件守卫
36 | // 在当前组件对象被创建前调用, 不能直接访问this(不是组件对象)
37 | // 但可以通过next(component => {}), 在回调函数中访问组件对象
38 | beforeRouteEnter (to, from, next) {
39 | next(component => {})
40 | },
41 | // 当前组件对象将要更新前调用, 可以访问this
42 | beforeRouteUpdate (to, from, next) {
43 |
44 | },
45 | // 在当前组件离开前调用, 可以访问this
46 | beforeRouteLeave (to, from, next) {
47 | next()
48 | }
49 |
50 | # 4. 导航解析流程
51 | 导航被触发。
52 | 在失活的组件里调用组件离开守卫: beforeRouteLeave()
53 | 调用全局的前置守卫: beforeEach()
54 | 在被激活的组件里调用组件进入守卫: beforeRouteEnter(), 函数内部可能会执行next(comp => {})
55 | 导航被确认。
56 | 创建组件对象
57 | 调用全局的后置钩子: afterEach()
58 | 调用组件中通过next(comp => {})指定的回调函数, 并将创建好的组件对象传入
59 |
60 | # 5. 应用(在vue项目中测试使用)
61 | 1). 针对部分/某个界面, 检查用户是否登陆
62 | a. 必须登陆, 如果没有跳转到登陆界面
63 | b. 不能登陆, 如果已经登陆, 跳转到特定界面
64 | 2). 在路由界面离开前, 做一些收尾工作(如清除定时器)
65 | 3). 常用的卫士回调函数:
66 | a. 全局前置卫士: beforeEach()
67 | b. 组件进入卫士: beforeRouteEnter() // 不能直接使用this
68 | c. 组件离开卫士: beforeRouteLeave()
69 |
70 |
71 | 需求:
72 | 1. 进入a/b必须登陆, 如果没有登陆自动跳转到登陆
73 | 2. 进入登陆界面时, 如果已经登陆了自动跳转到个人中心
--------------------------------------------------------------------------------
/static/css/reset.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Eric Meyer's Reset CSS v2.0 (http://meyerweb.com/eric/tools/css/reset/)
3 | * http://cssreset.com
4 | */
5 | html, body, div, span, applet, object, iframe,
6 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
7 | a, abbr, acronym, address, big, cite, code,
8 | del, dfn, em, img, ins, kbd, q, s, samp,
9 | small, strike, strong, sub, sup, tt, var,
10 | b, u, i, center,
11 | dl, dt, dd, ol, ul, li,
12 | fieldset, form, label, legend,
13 | table, caption, tbody, tfoot, thead, tr, th, td,
14 | article, aside, canvas, details, embed,
15 | figure, figcaption, footer, header,
16 | menu, nav, output, ruby, section, summary,
17 | time, mark, audio, video, input {
18 | margin: 0;
19 | padding: 0;
20 | border: 0;
21 | font-size: 100%;
22 | font-weight: normal;
23 | vertical-align: baseline;
24 | }
25 |
26 | /* HTML5 display-role reset for older browsers */
27 | article, aside, details, figcaption, figure,
28 | footer, header, menu, nav, section {
29 | display: block;
30 | }
31 |
32 | body {
33 | line-height: 1;
34 | }
35 |
36 | blockquote, q {
37 | quotes: none;
38 | }
39 |
40 | blockquote:before, blockquote:after,
41 | q:before, q:after {
42 | content: none;
43 | }
44 |
45 | table {
46 | border-collapse: collapse;
47 | border-spacing: 0;
48 | }
49 |
50 | /* custom */
51 | a {
52 | color: #7e8c8d;
53 | text-decoration: none;
54 | -webkit-backface-visibility: hidden;
55 | }
56 |
57 | li {
58 | list-style: none;
59 | }
60 |
61 | ::-webkit-scrollbar {
62 | width: 5px;
63 | height: 5px;
64 | }
65 |
66 | ::-webkit-scrollbar-track-piece {
67 | background-color: rgba(0, 0, 0, 0.2);
68 | -webkit-border-radius: 6px;
69 | }
70 |
71 | ::-webkit-scrollbar-thumb:vertical {
72 | height: 5px;
73 | background-color: rgba(125, 125, 125, 0.7);
74 | -webkit-border-radius: 6px;
75 | }
76 |
77 | ::-webkit-scrollbar-thumb:horizontal {
78 | width: 5px;
79 | background-color: rgba(125, 125, 125, 0.7);
80 | -webkit-border-radius: 6px;
81 | }
82 |
83 | html, body {
84 | width: 100%;
85 | height: 100%;
86 | }
87 |
88 | body {
89 | -webkit-text-size-adjust: none;
90 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
91 | }
92 |
93 | /*显示省略号*/
94 | .ellipsis{
95 | overflow: hidden;
96 | text-overflow: ellipsis;
97 | white-space: nowrap;
98 | }
--------------------------------------------------------------------------------
/src/components/Star/Star.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
40 |
41 |
93 |
--------------------------------------------------------------------------------
/src/components/RatingsFilter/RatingsFilter.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 全部{{totalRatingCount}}
6 |
7 |
8 | 推荐{{positiveRatingCount}}
9 |
10 |
11 | 吐槽{{negativeRatingCount}}
12 |
13 |
14 |
15 |
16 | 只看有内容的评价
17 |
18 |
19 |
20 |
21 |
47 |
48 |
91 |
--------------------------------------------------------------------------------
/src/router/routes.js:
--------------------------------------------------------------------------------
1 | /*
2 | 包含应用中所有路由配置的模块
3 | */
4 | // import MSite from '../pages/MSite/MSite.vue'
5 | // import Search from '../pages/Search/Search.vue'
6 | // import Order from '../pages/Order/Order.vue'
7 | // import Profile from '../pages/Profile/Profile.vue'
8 |
9 | // 1. 通过import()加载的模块会被单独打包(单独的js: code split)
10 | // 定义的路由component是一个函数, 函数在第一次被请求时才会执行
11 | const MSite = () => import('../pages/MSite/MSite.vue')
12 | const Search = () => import('../pages/Search/Search.vue')
13 | const Order = () => import('../pages/Order/Order.vue')
14 | const Profile = () => import('../pages/Profile/Profile.vue')
15 |
16 | import Login from '../pages/Login/Login.vue'
17 | import Shop from '../pages/Shop/Shop.vue'
18 | import ShopGoods from '../pages/Shop/ShopGoods/ShopGoods.vue'
19 | import ShopRatings from '../pages/Shop/ShopRatings/ShopRatings.vue'
20 | import ShopInfo from '../pages/Shop/ShopInfo/ShopInfo.vue'
21 | import NotFound from '../pages/NotFound/NotFound.vue'
22 |
23 | import A from '../pages/test/A.vue'
24 | import B from '../pages/test/B.vue'
25 | import B1 from '../pages/test/B1.vue'
26 | import B2 from '../pages/test/B2.vue'
27 |
28 | export default [
29 | {
30 | path: '/msite',
31 | component: MSite,
32 | meta: {
33 | showFooter: true
34 | }
35 | },
36 | {
37 | path: '/search',
38 | component: Search,
39 | meta: {
40 | showFooter: true
41 | }
42 | },
43 | {
44 | path: '/order',
45 | component: Order,
46 | meta: {
47 | showFooter: true
48 | }
49 | },
50 | {
51 | path: '/profile',
52 | component: Profile,
53 | meta: {
54 | showFooter: true
55 | }
56 | },
57 | {
58 | path: '/login',
59 | component: Login
60 | },
61 | {
62 | path: '/shop',
63 | component: Shop,
64 | children: [
65 | {
66 | path: '/shop/goods',
67 | component: ShopGoods
68 | },
69 | {
70 | path: '/shop/ratings',
71 | component: ShopRatings
72 | },
73 | {
74 | path: '/shop/info',
75 | component: ShopInfo
76 | },
77 |
78 | {
79 | path: '',
80 | redirect: '/shop/goods'
81 | }
82 | ]
83 | },
84 |
85 | {
86 | path: '/',
87 | redirect: '/msite'
88 | },
89 | {
90 | path: '/a',
91 | component: A
92 | },
93 | {
94 | path: '/b',
95 | component: B,
96 | children: [
97 | {
98 | path: '/b/b1',
99 | component: B1
100 | },
101 | {
102 | path: '/b/b2',
103 | component: B2
104 | },
105 | ]
106 | },
107 |
108 | { // 配置404组件, 放在最后
109 | path: '/*',
110 | component: NotFound
111 | },
112 | ]
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gshop-client",
3 | "version": "1.0.0",
4 | "description": "A Vue.js project",
5 | "author": "zxfjd3g <258147149@qq.com>",
6 | "private": true,
7 | "scripts": {
8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --host 192.168.16.38",
9 | "start": "npm run dev",
10 | "lint": "eslint --ext .js,.vue src",
11 | "build": "node build/build.js"
12 | },
13 | "dependencies": {
14 | "axios": "^0.18.0",
15 | "better-scroll": "^1.13.2",
16 | "mint-ui": "^2.2.13",
17 | "mockjs": "^1.0.1-beta3",
18 | "moment": "^2.23.0",
19 | "swiper": "^4.4.6",
20 | "vue": "^2.5.2",
21 | "vue-router": "^3.0.2",
22 | "vuex": "^3.0.1",
23 | "vue-lazyload": "1.2.6"
24 | },
25 | "devDependencies": {
26 | "autoprefixer": "^7.1.2",
27 | "babel-core": "^6.22.1",
28 | "babel-eslint": "^8.2.1",
29 | "babel-helper-vue-jsx-merge-props": "^2.0.3",
30 | "babel-loader": "^7.1.1",
31 | "babel-plugin-component": "^1.1.1",
32 | "babel-plugin-syntax-jsx": "^6.18.0",
33 | "babel-plugin-transform-runtime": "^6.22.0",
34 | "babel-plugin-transform-vue-jsx": "^3.5.0",
35 | "babel-preset-env": "^1.3.2",
36 | "babel-preset-stage-2": "^6.22.0",
37 | "chalk": "^2.0.1",
38 | "copy-webpack-plugin": "^4.0.1",
39 | "css-loader": "^0.28.0",
40 | "eslint": "^4.15.0",
41 | "eslint-config-standard": "^10.2.1",
42 | "eslint-friendly-formatter": "^3.0.0",
43 | "eslint-loader": "^1.7.1",
44 | "eslint-plugin-import": "^2.7.0",
45 | "eslint-plugin-node": "^5.2.0",
46 | "eslint-plugin-promise": "^3.4.0",
47 | "eslint-plugin-standard": "^3.0.1",
48 | "eslint-plugin-vue": "^4.0.0",
49 | "extract-text-webpack-plugin": "^3.0.0",
50 | "file-loader": "^1.1.4",
51 | "friendly-errors-webpack-plugin": "^1.6.1",
52 | "html-webpack-plugin": "^2.30.1",
53 | "node-notifier": "^5.1.2",
54 | "optimize-css-assets-webpack-plugin": "^3.2.0",
55 | "ora": "^1.2.0",
56 | "portfinder": "^1.0.13",
57 | "postcss-import": "^11.0.0",
58 | "postcss-loader": "^2.0.8",
59 | "postcss-url": "^7.2.1",
60 | "rimraf": "^2.6.0",
61 | "semver": "^5.3.0",
62 | "shelljs": "^0.7.6",
63 | "stylus": "^0.54.5",
64 | "stylus-loader": "^3.0.2",
65 | "uglifyjs-webpack-plugin": "^1.1.1",
66 | "url-loader": "^0.5.8",
67 | "vue-loader": "^13.3.0",
68 | "vue-style-loader": "^3.0.1",
69 | "vue-template-compiler": "^2.5.2",
70 | "webpack": "^3.6.0",
71 | "webpack-bundle-analyzer": "^2.9.0",
72 | "webpack-dev-server": "^2.9.1",
73 | "webpack-merge": "^4.1.0"
74 | },
75 | "engines": {
76 | "node": ">= 6.0.0",
77 | "npm": ">= 3.0.0"
78 | },
79 | "browserslist": [
80 | "> 1%",
81 | "last 2 versions",
82 | "not ie <= 8"
83 | ]
84 | }
85 |
--------------------------------------------------------------------------------
/config/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // Template version: 1.3.1
3 | // see http://vuejs-templates.github.io/webpack for documentation.
4 |
5 | const path = require('path')
6 |
7 | module.exports = {
8 | dev: {
9 |
10 | // Paths
11 | assetsSubDirectory: 'static',
12 | assetsPublicPath: '/',
13 | proxyTable: {
14 | '/api': { // 匹配所有以 '/api'开头的请求路径
15 | target: 'http://localhost:5000', // 代理目标的基础路径
16 | changeOrigin: true, // 支持跨域
17 | pathRewrite: {// 重写路径: 去掉路径中开头的'/api'
18 | '^/api': ''
19 | }
20 | },
21 | '/baidu': { // 匹配所有以 '/api'开头的请求路径
22 | target: 'http://www.baidu.com', // 代理目标的基础路径
23 | changeOrigin: true, // 支持跨域
24 | pathRewrite: {// 重写路径: 去掉路径中开头的'/api'
25 | '^/baidu': ''
26 | }
27 | }
28 | },
29 |
30 | // Various Dev Server settings
31 | host: 'localhost', // can be overwritten by process.env.HOST
32 | port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
33 | autoOpenBrowser: true,
34 | errorOverlay: true,
35 | notifyOnErrors: true,
36 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
37 |
38 | // Use Eslint Loader?
39 | // If true, your code will be linted during bundling and
40 | // linting errors and warnings will be shown in the console.
41 | useEslint: true,
42 | // If true, eslint errors and warnings will also be shown in the error overlay
43 | // in the browser.
44 | showEslintErrorsInOverlay: false,
45 |
46 | /**
47 | * Source Maps
48 | */
49 |
50 | // https://webpack.js.org/configuration/devtool/#development
51 | devtool: 'cheap-module-eval-source-map',
52 |
53 | // If you have problems debugging vue-files in devtools,
54 | // set this to false - it *may* help
55 | // https://vue-loader.vuejs.org/en/options.html#cachebusting
56 | cacheBusting: true,
57 |
58 | cssSourceMap: true
59 | },
60 |
61 | build: {
62 | // Template for index.html
63 | index: path.resolve(__dirname, '../dist/index.html'),
64 |
65 | // Paths
66 | assetsRoot: path.resolve(__dirname, '../dist'),
67 | assetsSubDirectory: 'static',
68 | assetsPublicPath: '/',
69 |
70 | /**
71 | * Source Maps
72 | */
73 |
74 | productionSourceMap: true,
75 | // https://webpack.js.org/configuration/devtool/#production
76 | devtool: '#source-map',
77 |
78 | // Gzip off by default as many popular static hosts such as
79 | // Surge or Netlify already gzip all static assets for you.
80 | // Before setting to `true`, make sure to:
81 | // npm install --save-dev compression-webpack-plugin
82 | productionGzip: false,
83 | productionGzipExtensions: ['js', 'css'],
84 |
85 | // Run the build command with an extra argument to
86 | // View the bundle analyzer report after build finishes:
87 | // `npm run build --report`
88 | // Set to `true` or `false` to always turn it on or off
89 | bundleAnalyzerReport: process.env.npm_config_report
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/store/modules/shop.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import {reqGoods, reqRatings, reqInfo} from '../../api'
3 | import {
4 | RECEIVE_GOODS,
5 | RECEIVE_RATINGS,
6 | RECEIVE_INFO,
7 | ADD_FOOD_COUNT,
8 | REDUCE_FOOD_COUNT
9 | } from '../mutation-types'
10 |
11 | const state = {
12 | goods: [], // 商品列表
13 | ratings: [], // 商家评价列表
14 | info: {}, // 商家信息
15 | cartFoods: [], // 购物车中food数组
16 | }
17 | const mutations = {
18 | [RECEIVE_INFO](state, {info}) {
19 | state.info = info
20 | },
21 |
22 | [RECEIVE_RATINGS](state, {ratings}) {
23 | state.ratings = ratings
24 | },
25 |
26 | [RECEIVE_GOODS](state, {goods}) {
27 | state.goods = goods
28 | },
29 |
30 | [ADD_FOOD_COUNT] (state, {food}) {
31 | if(!food.count) {
32 | // 给food添加一个新的属性, 内部不会进行数据劫持, 没有数据绑定
33 | // food.count = 1
34 | // 向响应式对象中添加一个属性,并确保这个新属性同样是响应式的
35 | Vue.set(food, 'count', 1)
36 | // 将food添加到购物车中
37 | state.cartFoods.push(food)
38 |
39 | } else {
40 | // 给food已有的属性值增加1
41 | food.count++
42 | }
43 |
44 | },
45 |
46 | [REDUCE_FOOD_COUNT] (state, {food}) {
47 | if(food.count>0) {
48 | food.count--
49 |
50 | if(food.count===0) {
51 | // 将food从购物车中删除
52 | state.cartFoods.splice(state.cartFoods.indexOf(food), 1)
53 | }
54 | }
55 | },
56 |
57 |
58 | }
59 | const actions = {
60 | async getGoods({commit}, cb) {
61 | const result = await reqGoods()
62 | if (result.code === 0) {
63 | const goods = result.data
64 | commit(RECEIVE_GOODS, {goods})
65 | typeof cb==='function' && cb()
66 | }
67 | },
68 |
69 | async getRatings({commit}, cb) {
70 | const result = await reqRatings()
71 | if (result.code === 0) {
72 | const ratings = result.data
73 | commit(RECEIVE_RATINGS, {ratings})
74 | typeof cb==='function' && cb()
75 | }
76 | },
77 |
78 | async getInfo({commit}) {
79 | const result = await reqInfo()
80 | if (result.code === 0) {
81 | const info = result.data
82 | commit(RECEIVE_INFO, {info})
83 | }
84 | },
85 |
86 | updateFoodCount ({commit}, {food, isAdd}) {
87 | if(isAdd) {
88 | commit(ADD_FOOD_COUNT, {food})
89 | } else {
90 | commit(REDUCE_FOOD_COUNT, {food})
91 | }
92 | }
93 | }
94 | const getters = {
95 | /*cartFoods (state) {
96 | const foods = []
97 | state.goods.forEach(good => {
98 | good.foods.forEach(food => {
99 | if(food.count>0) {
100 | foods.push(food)
101 | }
102 | })
103 | })
104 | return foods
105 | }*/
106 |
107 | totalCount (state) {
108 | return state.cartFoods.reduce((pre, food) => pre + food.count, 0)
109 | },
110 |
111 | totalPrice (state) {
112 | return state.cartFoods.reduce((pre, food) => pre + food.count*food.price, 0)
113 | },
114 |
115 | totalRatingCount (state) {
116 | return state.ratings.length
117 | },
118 |
119 | positiveRatingCount (state) {
120 | return state.ratings.reduce((pre, rating) => pre + (rating.rateType===0 ? 1 : 0), 0)
121 | },
122 |
123 | negativeRatingCount (state, getters) {
124 | return getters.totalRatingCount - getters.positiveRatingCount
125 | }
126 | }
127 |
128 | export default {
129 | state,
130 | mutations,
131 | actions,
132 | getters
133 | }
--------------------------------------------------------------------------------
/src/components/Food/Food.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
{{food.name}}
14 |
15 | 月售{{food.sellCount}}份
16 | 好评率{{food.rating}}%
17 |
18 |
19 | ¥{{food.price}}
20 | ¥{{food.oldPrice}}
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
51 |
52 |
167 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # day01
2 | ## 1. 项目开发准备
3 | 项目描述
4 | 技术选型
5 | API接口
6 |
7 | ## 2. 开启项目开发
8 | 使用脚手架创建项目
9 | 安装所有依赖/指定依赖
10 | 开发环境运行
11 | 生产环境打包与发布
12 |
13 | ## 3. 搭建项目整体界面结构
14 | stylus的理解和使用
15 | 结构化, 变量, 函数/minxin(混合)
16 | vue-router的理解和使用
17 | $router: 路由器对象, 包含一些操作路由的功能函数, 来实现编程式导航(跳转路由)
18 | $route: 当前路由对象, 一些当前路由信息数据的容器, path/meta/query/params
19 | 项目路由拆分
20 | 确定路由组件显示的区域
21 | 确定路由是几级路由
22 | 底部导航组件: FooterGuide
23 | 导航路由组件: MSite/Search/Order/Profile
24 |
25 | # day02
26 | ## 1. 抽取组件
27 | 头部组件: NavHeader, 通过slot来实现组件通信标签结构
28 | 商家列表组件: ShopList
29 |
30 | ## 2. 登陆路由组件
31 | 静态组件
32 | FooterGuide的显示/隐藏: 通过路由的meta
33 |
34 | ## 3. 后台应用
35 | 运行后台项目(启动mongodb服务),
36 | 使用postman测试后台接口, 如果不一致, 修改接口文档
37 |
38 | ## 4. 异步显示数据
39 | 封装ajax:
40 | promise+axios封装ajax请求的函数
41 | 封装每个接口对应的请求函数(能根据接口定义ajax请求函数)
42 | 解决ajax的跨越域问题: 配置代理, 对代理的理解
43 | vuex编码
44 | 创建所有相关的模块: store/index|state|mutations|actions|getters|mutation-types
45 | 设计state: 从后台获取的数据
46 | 实现actions:
47 | 定义异步action: async/await
48 | 流程: 发ajax获取数据, commit给mutation
49 | 实现mutations: 给状态赋值
50 | 实现index: 创建store对象
51 | main.js: 配置store
52 | 组件异步显示数据
53 | 在mounted()通过$store.dispatch('actionName')来异步获取后台数据到state中
54 | mapState(['xxx'])读取state中数据到组件中
55 | 在模板中显示xxx的数据
56 |
57 | ## 5. Star组件
58 | 创建组件, 设计组件的props
59 | 使用组件标签, 并传入相应的标签属性
60 | 完成组件编码: 使用计算属性
61 |
62 | # day03
63 |
64 | ## 1. 异步显示分类轮播
65 | 通过vuex获取categorys数组(发请求, 读取)
66 | 对数据进行整合一计算(维变为特定的二维数组)
67 | 使用Swiper显示轮播, 如何在界面更新之后创建Swiper对象?
68 | 1). 使用watch+$nextTick( () =>{界面更新之后立即执行})
69 | 2). 使用回调+$nextTick()
70 | 使用svg图片实现loading的效果
71 |
72 | ## 2. 登陆的前台效果
73 | 1). 切换登陆方式: loginWay
74 | 2). 手机号验证: right_phone + isRightPhone计算属性
75 | 3). 倒计时效果: computeTime + setInterval()
76 | 4). 密码显示/隐藏的切换: isShowPwd + transition
77 |
78 | # day04
79 | ## 1. 登陆的前后台交互效果
80 | 1). 一次性图形验证码:
81 | 通过
请求后台获取验证码图片显示
82 | 点击回调中更新img的src, 并携带时间戳参数, 更新验证码
83 | 2). 发送短信验证码
84 | 使用第三方短信平台接口
85 | 请求发送验证码短信
86 | 使用mint-ui实现对不同结果的不同提示效果
87 | 3). 短信登陆/注册
88 | 4). 密码登陆/注册
89 | 5). 前台表单验证
90 | 表单前台验证, 如果不通过, 提示
91 | 发送ajax请求, 得到返回的结果
92 | 根据结果的标识(code)来判断登陆请求是否成功
93 | 1: 不成功, 显示提示
94 | 0. 成功, 保存用户信息, 返回到个人中心
95 | 6). 自动登陆
96 | session与cookie的理解
97 | 后台将userid保存到session中
98 | App初始化过程中发请求获取user信息, 并保存到state
99 | 7). 退出登陆
100 | 请求退出登陆的接口, 重置state中的user
101 |
102 | ## 2. 搭建商家整体界面
103 | 1). 拆分界面路由: 嵌套路由
104 | 2). 路由的定义/配置|使用
105 |
106 | # day04
107 | ## 1. vuex的多模块编码
108 | 1). 设计多个模块
109 | msite
110 | user
111 | shop
112 | 2). 将state拆分到对应的模块中, 确定整个state的结构
113 | 3). 将mutation和action拆分到对应的模块中
114 | 4). 在组件中通过mapState读取特定模块的状态数据
115 | ...mapState({user: state => state.user.user})
116 |
117 | ## 2. 模拟(mock)数据/接口
118 | 1). 前后台分离的理解
119 | 区别前后台分离的应用和前后台不分离的应用
120 | 区别一般的HTTP请求和ajax请求
121 | 2). json数据设计的理解
122 | json数据的类型: 对象/数组/字符串/数值/布尔值
123 | json数据的组成: 结构(名称和类型)和值
124 | 3). mockjs的理解和使用
125 | 用来提供mock数据接口的库
126 | 生成随机数据, 拦截ajax请求
127 |
128 | ## 3. ShopHeader组件
129 | 1). 异步显示数据效果的编码流程
130 | ajax
131 | ajax请求函数
132 | 接口请求函数
133 | vuex
134 | modules/shop.js
135 | 组件
136 | dispatch(): 异步获取后台数据到vuex的state
137 | mapState(): 从vuex的state中读取对应的数据
138 | 模板中显示
139 | 2). 初始显示异常
140 | 情况: Cannot read property 'xxx' of undefined"
141 | 原因: 初始值是空对象, 内部没有数据, 而模块中直接显示3层表达式
142 | 解决: 使用v-if指令
143 | 3). vue transition动画
144 |
145 | xxx-enter-active / xxx-leave-active
146 | transition
147 | xxx-enter / xxx-leave-to
148 | 隐藏时的样式
149 |
150 | ## 4. ShopGoods组件
151 | 1). 动态展现列表数据
152 | 2). 基本滑动:
153 | 使用better-scroll
154 | 创建BScroll对象的时机
155 | watch + $nextTick()
156 | 自定义callback + $nextTick
157 | better-scroll禁用了原生的dom事件, 使用的是自定义事件
158 |
159 | ## 5. CartControl组件
160 | 1). 问题: 更新状态数据, 对应的界面不变化
161 | 原因: 给一个已有绑定的对象直接添加一个新的属性, 这个属性没有数据绑定
162 | 解决:
163 | Vue.set(obj, 'xxx', value)才有数据绑定
164 | this.$set(obj, 'xxx', value)才有数据绑定
165 | 2). vue transition
166 |
167 | # day05
168 |
169 | ## 1. ShopGoods组件滑动功能
170 | 1). 滑动右侧列表, 左侧会同步更新当前分类
171 | 1). 设计一个计算属性: currentIndex代表当前分类的下标
172 | 2). 相关数据
173 | 滚动的y坐标: scrollY---> 给右侧列表绑定一个滚动的监听
174 | 右侧分类的top数组: tops-->列表第一次显示之后统计
175 | 3). 计算的逻辑
176 | scrollY>=top && scrollY
2 |
3 |
4 |
5 |
8 |
12 |
13 |
14 |
33 |
34 |
35 |
39 |
40 |
41 |
42 |
43 |
44 |
145 |
146 |
--------------------------------------------------------------------------------
/src/components/ShopList/ShopList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
41 |
42 | -
43 |
44 |
45 | -
46 |
47 |
48 | -
49 |
50 |
51 | -
52 |
53 |
54 |
55 |
56 |
57 |
58 |
73 |
74 |
180 |
--------------------------------------------------------------------------------
/src/pages/Shop/ShopInfo/ShopInfo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 配送信息
6 |
7 |
8 | {{info.description}}
9 | 由商家配送提供配送,约{{info.deliveryTime}}分钟送达,距离{{info.distance}}
10 |
11 |
配送费¥{{info.deliveryPrice}}
12 |
13 |
14 |
15 |
16 |
17 |
18 | 活动与服务
19 |
20 |
21 |
22 | {{support.name}}
23 |
24 | {{support.content}}
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | 商家实景
33 |
34 |
35 | -
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | 商家信息
46 |
47 | -
48 | 品类
49 | {{info.category}}
50 |
51 | -
52 | 商家电话
53 | {{info.phone}}
54 |
55 | -
56 | 地址
57 | {{info.address}}
58 |
59 | -
60 | 营业时间
61 | {{info.workTime}}
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
129 |
130 |
240 |
--------------------------------------------------------------------------------
/src/pages/Shop/ShopGoods/ShopGoods.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
17 |
18 |
19 | -
20 |
{{good.name}}
21 |
22 | -
24 |
25 |
![]()
26 |
27 |
28 |
{{food.name}}
29 |
{{food.description}}
30 |
33 |
34 | ¥{{food.price}}
35 | ¥{{food.oldPrice}}
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
176 |
177 |
276 |
277 |
--------------------------------------------------------------------------------
/src/components/ShopCart/ShopCart.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
{{totalCount}}
11 |
12 |
¥{{totalPrice}}
13 |
另需配送费¥{{info.deliveryPrice}}元
14 |
15 |
16 |
17 | {{payText}}
18 |
19 |
20 |
21 |
22 |
23 |
27 |
28 |
29 | -
30 | {{food.name}}
31 |
¥{{food.price}}
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
126 |
127 |
283 |
--------------------------------------------------------------------------------
/src/pages/Shop/ShopRatings/ShopRatings.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
{{info.score}}
7 |
综合评分
8 |
高于周边商家90%
9 |
10 |
11 |
12 | 服务态度
13 |
14 | {{info.serviceScore}}
15 |
16 |
17 | 商品评分
18 |
19 | {{info.foodScore}}
20 |
21 | 送达时间
22 | {{info.deliveryTime}}分钟
23 |
24 |
25 |
26 |
27 |
28 |
29 |
33 |
34 |
35 |
36 | -
37 |
38 |
![]()
39 |
40 |
41 |
{{rating.username}}
42 |
43 |
44 | {{rating.deliveryTime}}
45 |
46 |
{{rating.text}}
47 |
48 |
49 | {{item}}
50 |
51 |
{{rating.rateTime | date-format}}
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
134 |
135 |
270 |
--------------------------------------------------------------------------------
/src/pages/Profile/Profile.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
27 |
43 |
81 |
95 |
96 |
99 |
100 |
101 | AAA
102 |
103 | BBB
104 |
105 | 去登陆
106 |
107 |
108 |
109 |
110 |
139 |
140 |
--------------------------------------------------------------------------------
/src/pages/Login/images/captcha.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/pages/Login/Login.vue:
--------------------------------------------------------------------------------
1 |
2 |
56 |
57 |
58 |
171 |
172 |
311 |
--------------------------------------------------------------------------------
/src/components/ShopHeader/ShopHeader.vue:
--------------------------------------------------------------------------------
1 |
2 |
109 |
110 |
111 |
112 |
131 |
132 |
507 |
--------------------------------------------------------------------------------
/API文档.md:
--------------------------------------------------------------------------------
1 | # 接口文档
2 |
3 | ## 目录:
4 | [1、根据经纬度获取位置详情](#1根据经纬度获取位置详情)
5 | [2、获取食品分类列表](#2获取食品分类列表)
6 | [3、根据经纬度获取商铺列表](#3根据经纬度获取商铺列表)
7 | [4、根据经纬度和关键字搜索商铺列表](#4根据经纬度和关键字搜索商铺列表)
8 | [5、获取一次性验证码](#5获取一次性验证码)
9 | [6、用户名密码登陆](#6用户名密码登陆)
10 | [7、发送短信验证码](#7发送短信验证码)
11 | [8、手机号验证码登陆](#8手机号验证码登陆)
12 | [9、根据会话获取用户信息](#9根据会话获取用户信息)
13 | [10、用户登出](#10用户登出)
14 |
15 | ## 1、根据经纬度获取位置详情
16 |
17 | ### 请求URL:
18 | http://localhost:5000/position/:geohash
19 |
20 | ### 示例:
21 | [http://localhost:5000/position/40.10038,116.36867](http://localhost:5000/position/40.10038,116.36867)
22 |
23 | ### 请求方式:
24 | GET
25 |
26 | ### 参数类型:param
27 |
28 | |参数 |是否必选 |类型 |说明
29 | |geohash |Y |string |经纬度
30 |
31 | ### 返回示例:
32 |
33 | {
34 | "code": 0,
35 | "data": {
36 | "address": "北京市昌平区337省道",
37 | "city": "北京市",
38 | "geohash": "40.10038,116.36867",
39 | "latitude": "40.10038",
40 | "longitude": "116.36867",
41 | "name": "昌平区北七家宏福科技园(337省道北)"
42 | }
43 | }
44 |
45 | ## 2、获取食品分类列表
46 |
47 | ### 请求URL:
48 | http://localhost:5000/index_category
49 |
50 | ### 请求方式:
51 | GET
52 |
53 | ### 参数类型:
54 | 无
55 |
56 | ### 返回示例:
57 | {
58 | "code": 0,
59 | data: [
60 | {
61 | id: 1,
62 | is_in_serving: true,
63 | description: "0元早餐0起送,每天都有新花样。",
64 | title: "预订早餐",
65 | link: "",
66 | image_url: "/d/49/7757ff22e8ab28e7dfa5f7e2c2692jpeg.jpeg",
67 | icon_url: "",
68 | title_color: "",
69 | __v: 0
70 | },
71 | {
72 | id: 65,
73 | is_in_serving: true,
74 | description: "",
75 | title: "土豪推荐",
76 | image_url: "/d/49/7757ff22e8ab28e7dfa5f7e2c2692jpeg.jpeg",
77 | link: "",
78 | icon_url: "",
79 | title_color: "",
80 | __v: 0
81 | },
82 | ... 共n条数据
83 | ]
84 | }
85 |
86 |
87 | ## 3、根据经纬度获取商铺列表
88 |
89 | ### 请求URL:
90 | http://localhost:5000/shops
91 |
92 | ### 示例:
93 | [http://localhost:5000/shops?latitude=40.10038&longitude=116.36867](http://localhost:5000/shops?latitude=40.10038&longitude=116.36867)
94 |
95 | ### 请求方式:
96 | GET
97 |
98 | ### 参数类型:query
99 | |参数 |是否必选 |类型 |说明|
100 | |latitude |Y |string |纬度|
101 | |longitude |Y |string |经度|
102 |
103 | ### 返回示例:
104 | {
105 | "code": 0,
106 | data: [
107 | {
108 | name: "肯德基",
109 | address: "上海市宝山区淞宝路155弄18号星月国际商务广场1层",
110 | id: 1,
111 | latitude: 31.38098,
112 | longitude: 121.50146,
113 | location: [
114 | 121.50146,
115 | 31.38098
116 | ],
117 | phone: "1232313124324",
118 | category: "快餐便当/简餐",
119 | supports: [
120 | {
121 | description: "已加入“外卖保”计划,食品安全有保障",
122 | icon_color: "999999",
123 | icon_name: "保",
124 | id: 7,
125 | name: "外卖保",
126 | _id: "591bec73c2bbc84a6328a1e5"
127 | }
128 | ],
129 | status: 0,
130 | recent_order_num: 615,
131 | rating_count: 389,
132 | rating: 1.6,
133 | promotion_info: "他依然有人有人有人有人有人",
134 | piecewise_agent_fee: {
135 | tips: "配送费约¥5"
136 | },
137 | opening_hours: [
138 | "8:30/20:30"
139 | ],
140 | license: {
141 | catering_service_license_image: "",
142 | business_license_image: ""
143 | },
144 | is_new: true,
145 | is_premium: true,
146 | image_path: "/img/shop/15c1513a00615.jpg",
147 | identification: {
148 | registered_number: "",
149 | registered_address: "",
150 | operation_period: "",
151 | licenses_scope: "",
152 | licenses_number: "",
153 | licenses_date: "",
154 | legal_person: "",
155 | identificate_date: null,
156 | identificate_agency: "",
157 | company_name: ""
158 | },
159 | float_minimum_order_amount: 20,
160 | float_delivery_fee: 5,
161 | distance: "19.5公里",
162 | order_lead_time: "40分钟",
163 | description: "好吃的",
164 | delivery_mode: {
165 | color: "57A9FF",
166 | id: 1,
167 | is_solid: true,
168 | text: "蜂鸟专送"
169 | },
170 | activities: [
171 | {
172 | icon_name: "减",
173 | name: "满减优惠",
174 | description: "满30减5,满60减8",
175 | icon_color: "f07373",
176 | id: 1,
177 | _id: "591bec73c2bbc84a6328a1e7"
178 | }
179 | ],
180 | }
181 | ]
182 | }
183 |
184 |
185 | ## 4、根据经纬度和关键字搜索商铺列表
186 |
187 | ### 请求URL:
188 | http://localhost:5000/search_shops
189 | 例子: http://localhost:5000/search_shops?keyword=test&geohash=40.10038,116.36867
190 |
191 | ### 请求方式:
192 | GET
193 |
194 | ### 参数类型:query
195 | |参数 |是否必选 |类型 |说明|
196 | |geohash |Y |string |经纬度
197 | |keyword |Y |string |关键字
198 |
199 | ### 返回示例:
200 | {
201 | "code": 0,
202 | "data": [
203 | {
204 | "name": "test_shop",
205 | "address": "广东省广州市海珠区马涌直街20号",
206 | "id": 1196,
207 | "latitude": 23.09499,
208 | "longitude": 113.26166,
209 | "location": [
210 | 113.26166,
211 | 23.09499
212 | ],
213 | "phone": "18320326523",
214 | "category": "鲜花蛋糕/面包",
215 | "supports": [
216 | {
217 | "description": "准时必达,超时秒赔",
218 | "icon_color": "57A9FF",
219 | "icon_name": "准",
220 | "id": 9,
221 | "name": "准时达",
222 | "_id": "5ad00b4febf543051ea2e5f6"
223 | },
224 | {
225 | "description": "该商家支持开发票,请在下单时填写好发票抬头",
226 | "icon_color": "999999",
227 | "icon_name": "票",
228 | "id": 4,
229 | "name": "开发票",
230 | "_id": "5ad00b4febf543051ea2e5f5"
231 | }
232 | ],
233 | "status": 1,
234 | "recent_order_num": 444,
235 | "rating_count": 246,
236 | "rating": 4,
237 | "promotion_info": "便靓正",
238 | "piecewise_agent_fee": {
239 | "tips": "配送费约¥5"
240 | },
241 | "opening_hours": [
242 | "09:00/21:30"
243 | ],
244 | "license": {
245 | "catering_service_license_image": "162bcabb96f9264.jpg",
246 | "business_license_image": "162bcabb9869263.jpg"
247 | },
248 | "is_new": true,
249 | "is_premium": true,
250 | "image_path": "162bcab6f889262.jpg",
251 | "identification": {
252 | "registered_number": "",
253 | "registered_address": "",
254 | "operation_period": "",
255 | "licenses_scope": "",
256 | "licenses_number": "",
257 | "licenses_date": "",
258 | "legal_person": "",
259 | "identificate_date": null,
260 | "identificate_agency": "",
261 | "company_name": ""
262 | },
263 | "float_minimum_order_amount": 20,
264 | "float_delivery_fee": 5,
265 | "distance": "2124.6公里",
266 | "order_lead_time": "31小时27分钟",
267 | "description": "普通商店",
268 | "delivery_mode": {
269 | "color": "57A9FF",
270 | "id": 1,
271 | "is_solid": true,
272 | "text": "蜂鸟专送"
273 | },
274 | "activities": [
275 | {
276 | "icon_name": "减",
277 | "name": "满减优惠",
278 | "description": "参加活动满减优惠",
279 | "icon_color": "f07373",
280 | "id": 1,
281 | "_id": "5ad00b4febf543051ea2e5f7"
282 | }
283 | ],
284 | "__v": 0
285 | },
286 | {
287 | "name": "test",
288 | "address": "浙江省杭州市余杭区高教路阿里巴巴西溪园区2号楼",
289 | "id": 1271,
290 | "latitude": 30.27817,
291 | "longitude": 120.022003,
292 | "location": [
293 | 120.022003,
294 | 30.27817
295 | ],
296 | "phone": "111",
297 | "category": "快餐便当/简餐",
298 | "supports": [
299 | {
300 | "description": "已加入“外卖保”计划,食品安全有保障",
301 | "icon_color": "999999",
302 | "icon_name": "保",
303 | "id": 7,
304 | "name": "外卖保",
305 | "_id": "5ad7101aebf543051ea30192"
306 | },
307 | {
308 | "description": "准时必达,超时秒赔",
309 | "icon_color": "57A9FF",
310 | "icon_name": "准",
311 | "id": 9,
312 | "name": "准时达",
313 | "_id": "5ad7101aebf543051ea30191"
314 | },
315 | {
316 | "description": "该商家支持开发票,请在下单时填写好发票抬头",
317 | "icon_color": "999999",
318 | "icon_name": "票",
319 | "id": 4,
320 | "name": "开发票",
321 | "_id": "5ad7101aebf543051ea30190"
322 | }
323 | ],
324 | "status": 1,
325 | "recent_order_num": 820,
326 | "rating_count": 305,
327 | "rating": 4.2,
328 | "promotion_info": "111",
329 | "piecewise_agent_fee": {
330 | "tips": "配送费约¥5"
331 | },
332 | "opening_hours": [
333 | "05:30/05:45"
334 | ],
335 | "license": {
336 | "catering_service_license_image": "162d816cf909817.png",
337 | "business_license_image": "162d816c82e9816.png"
338 | },
339 | "is_new": true,
340 | "is_premium": true,
341 | "image_path": "162d81696a79815.png",
342 | "identification": {
343 | "registered_number": "",
344 | "registered_address": "",
345 | "operation_period": "",
346 | "licenses_scope": "",
347 | "licenses_number": "",
348 | "licenses_date": "",
349 | "legal_person": "",
350 | "identificate_date": null,
351 | "identificate_agency": "",
352 | "company_name": ""
353 | },
354 | "float_minimum_order_amount": 20,
355 | "float_delivery_fee": 5,
356 | "distance": "1265.1公里",
357 | "order_lead_time": "18小时13分钟",
358 | "description": "111",
359 | "delivery_mode": {
360 | "color": "57A9FF",
361 | "id": 1,
362 | "is_solid": true,
363 | "text": "蜂鸟专送"
364 | },
365 | "activities": [],
366 | "__v": 0
367 | }
368 | ]
369 | }
370 |
371 | ## 5、获取一次性验证码
372 |
373 | ### 请求URL:
374 | http://localhost:5000/captcha
375 |
376 | ### 请求方式:
377 | GET
378 |
379 | ### 返回示例:
380 |
392 |
393 |
394 | ## 6、用户名密码登陆
395 |
396 | ### 请求URL:
397 | http://localhost:5000/login_pwd
398 |
399 | ### 请求方式:
400 | POST
401 |
402 | ### 参数类型: 请求体
403 |
404 | |参数 |是否必选 |类型 |说明
405 | |name |Y |string |用户名
406 | |pwd |Y |string |密码
407 | |captcha |Y |string |图片验证码
408 |
409 |
410 | ### 返回示例:
411 | * 登陆成功
412 | {
413 | "code": 0,
414 | "data": {
415 | "_id": "5a9cd9c6ad5b2d34d42b385d",
416 | "name": "aaa"
417 | }
418 | }
419 | * 登陆失败
420 | {
421 | "code": 1,
422 | "msg": "用户名或密码不正确!"
423 | }
424 |
425 |
426 | ## 7、发送短信验证码
427 |
428 | ### 请求URL:
429 | http://localhost:5000/sendcode
430 |
431 | ### 示例:
432 | [http://localhost:5000/sendcode?phone=13716962779](http://localhost:5000/sendcode?phone=13716962779)
433 |
434 | ### 请求方式:
435 | GET
436 |
437 | ### 参数类型: query
438 |
439 | |参数 |是否必选 |类型 |说明
440 | |phone |Y |string |手机号
441 |
442 | ### 返回示例:
443 | 成功
444 | {
445 | "code": 0,
446 | }
447 | 失败
448 | {
449 | "code": 1,
450 | msg: '短信验证码发送失败'
451 | }
452 |
453 |
454 | ## 8、手机号验证码登陆
455 |
456 | ### 请求URL:
457 | http://localhost:5000/login_sms
458 |
459 | ### 请求方式:
460 | POST
461 |
462 | ### 参数类型: 请求体
463 |
464 | |参数 |是否必选 |类型 |说明
465 | |phone |Y |string |手机号
466 | |code |Y |string |验证码
467 |
468 | ### 返回示例:
469 | * 登陆成功
470 | {
471 | "code": 0,
472 | "data": {
473 | "_id": "5a9cd9c6ad5b2d34d42b385d",
474 | "phone": "13716962779"
475 | }
476 | }
477 | * 登陆失败
478 | {
479 | "code": 1,
480 | "msg": "手机号或验证码不正确"
481 | }
482 |
483 | ### 9、根据会话获取用户信息
484 |
485 | #### 请求URL:
486 | http://localhost:5000/userinfo
487 |
488 | #### 请求方式:
489 | GET
490 |
491 | #### 返回示例:
492 | * 获取成功
493 | {
494 | "code": 0,
495 | "data": {
496 | "_id": "5a9cd9c6ad5b2d34d42b385d",
497 | "phone": "13716962779"
498 | }
499 | }
500 | * 获取失败
501 | {
502 | "code": 1,
503 | "msg": "请先登陆"
504 | }
505 |
506 |
507 | ### 10、用户登出
508 |
509 | #### 请求URL:
510 | http://localhost:5000/logout
511 |
512 | #### 请求方式:
513 | GET
514 |
515 | #### 返回示例:
516 | {code: 0}
--------------------------------------------------------------------------------