├── .babelrc ├── .editorconfig ├── .gitattributes ├── .gitignore ├── .postcssrc.js ├── README.md ├── build ├── build.js ├── check-versions.js ├── dev-client.js ├── dev-server.js ├── utils.js ├── vue-loader.conf.js ├── webpack.base.conf.js ├── webpack.dev.conf.js └── webpack.prod.conf.js ├── config ├── default.js ├── dev.env.js ├── index.js └── prod.env.js ├── index.html ├── package.json ├── server.js ├── server ├── controller │ ├── restaurant.js │ └── user.js ├── db │ └── db.js ├── middleware │ ├── checkToken.js │ └── createToken.js └── routes │ └── routes.js ├── src ├── API │ └── axios.js ├── App.vue ├── assets │ ├── css │ │ ├── icon.css │ │ └── reset.css │ ├── fonts │ │ ├── icomoon.eot │ │ ├── icomoon.svg │ │ ├── icomoon.ttf │ │ └── icomoon.woff │ └── img │ │ ├── dl.jpg │ │ ├── err.jpg │ │ └── shyj.jpg ├── components │ └── index │ │ ├── header.vue │ │ └── restaurantList.vue ├── main.js ├── page │ ├── err.vue │ ├── index.vue │ ├── login.vue │ └── register.vue ├── router │ └── index.js └── store │ ├── index.js │ └── modules │ ├── index.js │ └── login.js └── static ├── .gitkeep └── img ├── dl.jpg └── shyj.jpg /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { "modules": false }], 4 | "stage-2" 5 | ], 6 | "plugins": ["transform-runtime"], 7 | "comments": false, 8 | "env": { 9 | "test": { 10 | "presets": ["env", "stage-2"], 11 | "plugins": [ "istanbul" ] 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 4 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea/ 3 | node_modules/ 4 | dist/ 5 | npm-debug.log* 6 | yarn-debug.log* 7 | yarn-error.log* 8 | -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | // to edit target browsers: use "browserlist" field in package.json 6 | "autoprefixer": {} 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue_fast 2 | 3 | > 迅捷点餐,简单的实现了注册、登陆、获取用户信息、获取餐厅列表、以及无限加载列表功能、实现了登陆页面拦截(为方便测试,有效期设置为 30s 进行监测,普通生产情况下可以设置为更长的时间) 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # 下载依赖 9 | npm install 10 | 11 | # 启动前端服务 12 | npm run dev 13 | 14 | # 前端编译 15 | npm run build 16 | 17 | # 启动后端服务 18 | npm run server 19 | 20 | # 启动MongoDB (必须保证本地安装好MongoDB) 21 | 22 | # win下MongoDB安装方法 23 | http://blog.csdn.net/u013066244/article/details/53838721 24 | 25 | 26 | -------------------------------------------------------------------------------- /build/build.js: -------------------------------------------------------------------------------- 1 | require('./check-versions')() 2 | 3 | process.env.NODE_ENV = 'production' 4 | 5 | var ora = require('ora') 6 | var rm = require('rimraf') 7 | var path = require('path') 8 | var chalk = require('chalk') 9 | var webpack = require('webpack') 10 | var config = require('../config') 11 | var webpackConfig = require('./webpack.prod.conf') 12 | 13 | var spinner = ora('building for production...') 14 | spinner.start() 15 | 16 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { 17 | if (err) throw err 18 | webpack(webpackConfig, function (err, stats) { 19 | spinner.stop() 20 | if (err) throw err 21 | process.stdout.write(stats.toString({ 22 | colors: true, 23 | modules: false, 24 | children: false, 25 | chunks: false, 26 | chunkModules: false 27 | }) + '\n\n') 28 | 29 | console.log(chalk.cyan(' Build complete.\n')) 30 | console.log(chalk.yellow( 31 | ' Tip: built files are meant to be served over an HTTP server.\n' + 32 | ' Opening index.html over file:// won\'t work.\n' 33 | )) 34 | }) 35 | }) 36 | -------------------------------------------------------------------------------- /build/check-versions.js: -------------------------------------------------------------------------------- 1 | var chalk = require('chalk') 2 | var semver = require('semver') 3 | var packageConfig = require('../package.json') 4 | var shell = require('shelljs') 5 | function exec (cmd) { 6 | return require('child_process').execSync(cmd).toString().trim() 7 | } 8 | 9 | var versionRequirements = [ 10 | { 11 | name: 'node', 12 | currentVersion: semver.clean(process.version), 13 | versionRequirement: packageConfig.engines.node 14 | }, 15 | ] 16 | 17 | if (shell.which('npm')) { 18 | versionRequirements.push({ 19 | name: 'npm', 20 | currentVersion: exec('npm --version'), 21 | versionRequirement: packageConfig.engines.npm 22 | }) 23 | } 24 | 25 | module.exports = function () { 26 | var warnings = [] 27 | for (var i = 0; i < versionRequirements.length; i++) { 28 | var mod = versionRequirements[i] 29 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 30 | warnings.push(mod.name + ': ' + 31 | chalk.red(mod.currentVersion) + ' should be ' + 32 | chalk.green(mod.versionRequirement) 33 | ) 34 | } 35 | } 36 | 37 | if (warnings.length) { 38 | console.log('') 39 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 40 | console.log() 41 | for (var i = 0; i < warnings.length; i++) { 42 | var warning = warnings[i] 43 | console.log(' ' + warning) 44 | } 45 | console.log() 46 | process.exit(1) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /build/dev-client.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | require('eventsource-polyfill') 3 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') 4 | 5 | hotClient.subscribe(function (event) { 6 | if (event.action === 'reload') { 7 | window.location.reload() 8 | } 9 | }) 10 | -------------------------------------------------------------------------------- /build/dev-server.js: -------------------------------------------------------------------------------- 1 | require('./check-versions')() 2 | 3 | var config = require('../config') 4 | if (!process.env.NODE_ENV) { 5 | process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV) 6 | } 7 | 8 | var opn = require('opn') 9 | var path = require('path') 10 | var express = require('express') 11 | var webpack = require('webpack') 12 | var proxyMiddleware = require('http-proxy-middleware') 13 | var webpackConfig = require('./webpack.dev.conf') 14 | 15 | // default port where dev server listens for incoming traffic 16 | var port = process.env.PORT || config.dev.port 17 | // automatically open browser, if not set will be false 18 | var autoOpenBrowser = !!config.dev.autoOpenBrowser 19 | // Define HTTP proxies to your custom API backend 20 | // https://github.com/chimurai/http-proxy-middleware 21 | var proxyTable = config.dev.proxyTable 22 | 23 | var app = express() 24 | var compiler = webpack(webpackConfig) 25 | 26 | var devMiddleware = require('webpack-dev-middleware')(compiler, { 27 | publicPath: webpackConfig.output.publicPath, 28 | quiet: true 29 | }) 30 | 31 | var hotMiddleware = require('webpack-hot-middleware')(compiler, { 32 | log: () => {} 33 | }) 34 | // force page reload when html-webpack-plugin template changes 35 | compiler.plugin('compilation', function (compilation) { 36 | compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { 37 | hotMiddleware.publish({ action: 'reload' }) 38 | cb() 39 | }) 40 | }) 41 | 42 | // proxy api requests 43 | Object.keys(proxyTable).forEach(function (context) { 44 | var options = proxyTable[context] 45 | if (typeof options === 'string') { 46 | options = { target: options } 47 | } 48 | app.use(proxyMiddleware(options.filter || context, options)) 49 | }) 50 | 51 | // handle fallback for HTML5 history API 52 | app.use(require('connect-history-api-fallback')()) 53 | 54 | // serve webpack bundle output 55 | app.use(devMiddleware) 56 | 57 | // enable hot-reload and state-preserving 58 | // compilation error display 59 | app.use(hotMiddleware) 60 | 61 | // serve pure static assets 62 | var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) 63 | app.use(staticPath, express.static('./src/assets')) 64 | 65 | /* 66 | 67 | var request = require('request') 68 | var bodyParser = require('body-parser') 69 | app.use(bodyParser.urlencoded({ extended: true })) 70 | app.use(bodyParser.json()) 71 | 72 | var API = 'http://test1-pawfhd.pingan.com.cn:31080/pawf-nop/rest/flowCrowdFunding/' 73 | app.post('/:apiName',function (req,res,next) { 74 | request.post({ 75 | url:API + req.params.apiName, 76 | form: req.body 77 | }, function(err,httpResponse,body){ 78 | try { 79 | res.json(JSON.parse(body)) 80 | } catch(err) { 81 | res.send(err.msg) 82 | } 83 | }) 84 | }) 85 | */ 86 | 87 | 88 | var uri = 'http://localhost:' + port 89 | 90 | var _resolve 91 | var readyPromise = new Promise(resolve => { 92 | _resolve = resolve 93 | }) 94 | 95 | console.log('> Starting dev server...') 96 | devMiddleware.waitUntilValid(() => { 97 | console.log('> Listening at ' + uri + '\n') 98 | // when env is testing, don't need open it 99 | if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') { 100 | opn(uri) 101 | } 102 | _resolve() 103 | }) 104 | 105 | var server = app.listen(port) 106 | 107 | module.exports = { 108 | ready: readyPromise, 109 | close: () => { 110 | server.close() 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /build/utils.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 4 | 5 | exports.assetsPath = function (_path) { 6 | var assetsSubDirectory = process.env.NODE_ENV === 'production' 7 | ? config.build.assetsSubDirectory 8 | : config.dev.assetsSubDirectory 9 | return path.posix.join(assetsSubDirectory, _path) 10 | } 11 | 12 | exports.cssLoaders = function (options) { 13 | options = options || {} 14 | 15 | var cssLoader = { 16 | loader: 'css-loader', 17 | options: { 18 | minimize: process.env.NODE_ENV === 'production', 19 | sourceMap: options.sourceMap 20 | } 21 | } 22 | 23 | // generate loader string to be used with extract text plugin 24 | function generateLoaders (loader, loaderOptions) { 25 | var loaders = [cssLoader] 26 | if (loader) { 27 | loaders.push({ 28 | loader: loader + '-loader', 29 | options: Object.assign({}, loaderOptions, { 30 | sourceMap: options.sourceMap 31 | }) 32 | }) 33 | } 34 | 35 | // Extract CSS when that option is specified 36 | // (which is the case during production build) 37 | if (options.extract) { 38 | return ExtractTextPlugin.extract({ 39 | use: loaders, 40 | fallback: 'vue-style-loader' 41 | }) 42 | } else { 43 | return ['vue-style-loader'].concat(loaders) 44 | } 45 | } 46 | 47 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html 48 | return { 49 | css: generateLoaders(), 50 | postcss: generateLoaders(), 51 | less: generateLoaders('less'), 52 | sass: generateLoaders('sass', { indentedSyntax: true }), 53 | scss: generateLoaders('sass'), 54 | stylus: generateLoaders('stylus'), 55 | styl: generateLoaders('stylus') 56 | } 57 | } 58 | 59 | // Generate loaders for standalone style files (outside of .vue) 60 | exports.styleLoaders = function (options) { 61 | var output = [] 62 | var loaders = exports.cssLoaders(options) 63 | for (var extension in loaders) { 64 | var loader = loaders[extension] 65 | output.push({ 66 | test: new RegExp('\\.' + extension + '$'), 67 | use: loader 68 | }) 69 | } 70 | return output 71 | } 72 | -------------------------------------------------------------------------------- /build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | var utils = require('./utils') 2 | var config = require('../config') 3 | var isProduction = process.env.NODE_ENV === 'production' 4 | 5 | module.exports = { 6 | loaders: utils.cssLoaders({ 7 | sourceMap: isProduction 8 | ? config.build.productionSourceMap 9 | : config.dev.cssSourceMap, 10 | extract: isProduction 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var utils = require('./utils') 3 | var config = require('../config') 4 | var vueLoaderConfig = require('./vue-loader.conf') 5 | 6 | function resolve (dir) { 7 | return path.join(__dirname, '..', dir) 8 | } 9 | 10 | module.exports = { 11 | entry: { 12 | app: './src/main.js' 13 | }, 14 | output: { 15 | path: config.build.assetsRoot, 16 | filename: '[name].js', 17 | publicPath: process.env.NODE_ENV === 'production' 18 | ? config.build.assetsPublicPath 19 | : config.dev.assetsPublicPath 20 | }, 21 | resolve: { 22 | extensions: ['.js', '.vue', '.json'], 23 | alias: { 24 | 'vue$': 'vue/dist/vue.esm.js', 25 | '@': resolve('src') 26 | } 27 | }, 28 | module: { 29 | rules: [ 30 | { 31 | test: /\.vue$/, 32 | loader: 'vue-loader', 33 | options: vueLoaderConfig 34 | }, 35 | { 36 | test: /\.js$/, 37 | loader: 'babel-loader', 38 | include: [resolve('src'), resolve('test')] 39 | }, 40 | { 41 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 42 | loader: 'url-loader', 43 | options: { 44 | limit: 10000, 45 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 46 | } 47 | }, 48 | { 49 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 50 | loader: 'url-loader', 51 | options: { 52 | limit: 10000, 53 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 54 | } 55 | } 56 | ] 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | var utils = require('./utils') 2 | var webpack = require('webpack') 3 | var config = require('../config') 4 | var merge = require('webpack-merge') 5 | var baseWebpackConfig = require('./webpack.base.conf') 6 | var HtmlWebpackPlugin = require('html-webpack-plugin') 7 | var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 8 | 9 | // add hot-reload related code to entry chunks 10 | Object.keys(baseWebpackConfig.entry).forEach(function (name) { 11 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) 12 | }) 13 | 14 | module.exports = merge(baseWebpackConfig, { 15 | module: { 16 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) 17 | }, 18 | // cheap-module-eval-source-map is faster for development 19 | devtool: '#cheap-module-eval-source-map', 20 | plugins: [ 21 | new webpack.DefinePlugin({ 22 | 'process.env': config.dev.env 23 | }), 24 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage 25 | new webpack.HotModuleReplacementPlugin(), 26 | new webpack.NoEmitOnErrorsPlugin(), 27 | // https://github.com/ampedandwired/html-webpack-plugin 28 | new HtmlWebpackPlugin({ 29 | filename: 'index.html', 30 | template: 'index.html', 31 | inject: true 32 | }), 33 | new FriendlyErrorsPlugin() 34 | ] 35 | }) 36 | -------------------------------------------------------------------------------- /build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var utils = require('./utils') 3 | var webpack = require('webpack') 4 | var config = require('../config') 5 | var merge = require('webpack-merge') 6 | var baseWebpackConfig = require('./webpack.base.conf') 7 | var CopyWebpackPlugin = require('copy-webpack-plugin') 8 | var HtmlWebpackPlugin = require('html-webpack-plugin') 9 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 10 | var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') 11 | 12 | var env = config.build.env 13 | 14 | var webpackConfig = merge(baseWebpackConfig, { 15 | module: { 16 | rules: utils.styleLoaders({ 17 | sourceMap: config.build.productionSourceMap, 18 | extract: true 19 | }) 20 | }, 21 | devtool: config.build.productionSourceMap ? '#source-map' : false, 22 | output: { 23 | path: config.build.assetsRoot, 24 | filename: utils.assetsPath('js/[name].[chunkhash].js'), 25 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 26 | }, 27 | plugins: [ 28 | // http://vuejs.github.io/vue-loader/en/workflow/production.html 29 | new webpack.DefinePlugin({ 30 | 'process.env': env 31 | }), 32 | new webpack.optimize.UglifyJsPlugin({ 33 | compress: { 34 | warnings: false 35 | }, 36 | sourceMap: true 37 | }), 38 | // extract css into its own file 39 | new ExtractTextPlugin({ 40 | filename: utils.assetsPath('css/[name].[contenthash].css') 41 | }), 42 | // Compress extracted CSS. We are using this plugin so that possible 43 | // duplicated CSS from different components can be deduped. 44 | new OptimizeCSSPlugin({ 45 | cssProcessorOptions: { 46 | safe: true 47 | } 48 | }), 49 | // generate dist index.html with correct asset hash for caching. 50 | // you can customize output by editing /index.html 51 | // see https://github.com/ampedandwired/html-webpack-plugin 52 | new HtmlWebpackPlugin({ 53 | filename: config.build.index, 54 | template: 'index.html', 55 | inject: true, 56 | minify: { 57 | removeComments: true, 58 | collapseWhitespace: true, 59 | removeAttributeQuotes: true 60 | // more options: 61 | // https://github.com/kangax/html-minifier#options-quick-reference 62 | }, 63 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 64 | chunksSortMode: 'dependency' 65 | }), 66 | // split vendor js into its own file 67 | new webpack.optimize.CommonsChunkPlugin({ 68 | name: 'vendor', 69 | minChunks: function (module, count) { 70 | // any required modules inside node_modules are extracted to vendor 71 | return ( 72 | module.resource && 73 | /\.js$/.test(module.resource) && 74 | module.resource.indexOf( 75 | path.join(__dirname, '../node_modules') 76 | ) === 0 77 | ) 78 | } 79 | }), 80 | // extract webpack runtime and module manifest to its own file in order to 81 | // prevent vendor hash from being updated whenever app bundle is updated 82 | new webpack.optimize.CommonsChunkPlugin({ 83 | name: 'manifest', 84 | chunks: ['vendor'] 85 | }), 86 | // copy custom static assets 87 | new CopyWebpackPlugin([ 88 | { 89 | from: path.resolve(__dirname, '../static'), 90 | to: config.build.assetsSubDirectory, 91 | ignore: ['.*'] 92 | } 93 | ]) 94 | ] 95 | }) 96 | 97 | if (config.build.productionGzip) { 98 | var CompressionWebpackPlugin = require('compression-webpack-plugin') 99 | 100 | webpackConfig.plugins.push( 101 | new CompressionWebpackPlugin({ 102 | asset: '[path].gz[query]', 103 | algorithm: 'gzip', 104 | test: new RegExp( 105 | '\\.(' + 106 | config.build.productionGzipExtensions.join('|') + 107 | ')$' 108 | ), 109 | threshold: 10240, 110 | minRatio: 0.8 111 | }) 112 | ) 113 | } 114 | 115 | if (config.build.bundleAnalyzerReport) { 116 | var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin 117 | webpackConfig.plugins.push(new BundleAnalyzerPlugin()) 118 | } 119 | 120 | module.exports = webpackConfig 121 | -------------------------------------------------------------------------------- /config/default.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | port: 3000, 3 | mongodb: 'mongodb://localhost/fast' 4 | } 5 | -------------------------------------------------------------------------------- /config/dev.env.js: -------------------------------------------------------------------------------- 1 | var merge = require('webpack-merge') 2 | var prodEnv = require('./prod.env') 3 | 4 | module.exports = merge(prodEnv, { 5 | NODE_ENV: '"development"' 6 | }) 7 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | // see http://vuejs-templates.github.io/webpack for documentation. 2 | var path = require('path') 3 | 4 | module.exports = { 5 | build: { 6 | env: require('./prod.env'), 7 | index: path.resolve(__dirname, '../dist/index.html'), 8 | assetsRoot: path.resolve(__dirname, '../dist'), 9 | assetsSubDirectory: 'static', 10 | assetsPublicPath: './', 11 | productionSourceMap: true, 12 | // Gzip off by default as many popular static hosts such as 13 | // Surge or Netlify already gzip all static assets for you. 14 | // Before setting to `true`, make sure to: 15 | // npm install --save-dev compression-webpack-plugin 16 | productionGzip: false, 17 | productionGzipExtensions: ['js', 'css'], 18 | // Run the build command with an extra argument to 19 | // View the bundle analyzer report after build finishes: 20 | // `npm run build --report` 21 | // Set to `true` or `false` to always turn it on or off 22 | bundleAnalyzerReport: process.env.npm_config_report 23 | }, 24 | dev: { 25 | env: require('./dev.env'), 26 | port: 8080, 27 | autoOpenBrowser: true, 28 | assetsSubDirectory: 'assets', 29 | assetsPublicPath: '/', 30 | proxyTable: { 31 | '/api': { 32 | target: 'http://localhost:3000', 33 | changeOrigin: true 34 | } 35 | }, 36 | // CSS Sourcemaps off by default because relative paths are "buggy" 37 | // with this option, according to the CSS-Loader README 38 | // (https://github.com/webpack/css-loader#sourcemaps) 39 | // In our experience, they generally work as expected, 40 | // just be aware of this issue when enabling this option. 41 | cssSourceMap: false 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /config/prod.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: '"production"' 3 | } 4 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 迅捷点餐 7 | 8 | 9 |
10 | 11 |
12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue_fast", 3 | "version": "1.0.0", 4 | "description": "迅捷点餐", 5 | "author": "", 6 | "private": true, 7 | "scripts": { 8 | "dev": "node build/dev-server.js", 9 | "start": "node build/dev-server.js", 10 | "build": "node build/build.js", 11 | "server": "node server.js" 12 | }, 13 | "dependencies": { 14 | "axios": "^0.16.1", 15 | "lodash": "^4.17.4", 16 | "mint-ui": "^2.2.6", 17 | "vue": "^2.2.6", 18 | "vue-router": "^2.3.1", 19 | "vue-validator": "^3.0.0-alpha.2", 20 | "vuelidate": "^0.4.3", 21 | "vuex": "^2.3.1" 22 | }, 23 | "devDependencies": { 24 | "autoprefixer": "^6.7.2", 25 | "babel-core": "^6.22.1", 26 | "babel-loader": "^6.2.10", 27 | "babel-plugin-transform-runtime": "^6.22.0", 28 | "babel-preset-env": "^1.3.2", 29 | "babel-preset-stage-2": "^6.22.0", 30 | "babel-register": "^6.22.0", 31 | "body-parser": "^1.17.2", 32 | "chalk": "^1.1.3", 33 | "compression": "^1.6.2", 34 | "config-lite": "^2.0.0", 35 | "connect-history-api-fallback": "^1.3.0", 36 | "cookie-parser": "^1.4.3", 37 | "copy-webpack-plugin": "^4.0.1", 38 | "css-loader": "^0.28.0", 39 | "eventsource-polyfill": "^0.9.6", 40 | "exif-js": "^2.2.1", 41 | "express": "^4.14.1", 42 | "extract-text-webpack-plugin": "^2.0.0", 43 | "file-loader": "^0.11.1", 44 | "friendly-errors-webpack-plugin": "^1.1.3", 45 | "html-webpack-plugin": "^2.28.0", 46 | "http-proxy-middleware": "^0.17.3", 47 | "jsonwebtoken": "^7.4.1", 48 | "less": "^2.7.2", 49 | "less-loader": "^4.0.3", 50 | "moment": "^2.18.1", 51 | "mongoose": "^4.10.2", 52 | "morgan": "^1.8.1", 53 | "multiparty": "^4.1.3", 54 | "objectid-to-timestamp": "^1.3.0", 55 | "opn": "^4.0.2", 56 | "optimize-css-assets-webpack-plugin": "^1.3.0", 57 | "ora": "^1.2.0", 58 | "path": "^0.12.7", 59 | "rimraf": "^2.6.0", 60 | "semver": "^5.3.0", 61 | "serve-favicon": "^2.4.3", 62 | "sha1": "^1.1.1", 63 | "shelljs": "^0.7.6", 64 | "url-loader": "^0.5.8", 65 | "vue-loader": "^11.3.4", 66 | "vue-style-loader": "^2.0.5", 67 | "vue-template-compiler": "^2.2.6", 68 | "webpack": "^2.3.3", 69 | "webpack-bundle-analyzer": "^2.2.1", 70 | "webpack-dev-middleware": "^1.10.0", 71 | "webpack-hot-middleware": "^2.18.0", 72 | "webpack-merge": "^4.1.0" 73 | }, 74 | "engines": { 75 | "node": ">= 4.0.0", 76 | "npm": ">= 3.0.0" 77 | }, 78 | "browserslist": [ 79 | "> 1%", 80 | "last 2 versions", 81 | "not ie <= 8" 82 | ] 83 | } 84 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by lstfw on 2017/5/23. 3 | */ 4 | const express = require('express'); 5 | const path = require('path'); 6 | const bodyParser = require('body-parser'); 7 | const cookieParser = require('cookie-parser'); 8 | const favicon = require('serve-favicon'); 9 | const logger = require('morgan'); 10 | const routes = require('./server/routes/routes.js'); 11 | const config = require('config-lite')(__dirname); 12 | const compression = require('compression'); 13 | const app = express(); 14 | 15 | 16 | app.use(logger('dev')); 17 | app.use(bodyParser.json()); 18 | app.use(bodyParser.urlencoded({ extended: false })); 19 | app.use(cookieParser()); 20 | 21 | app.use(compression({ threshold: 0 })); 22 | app.use('/api', routes); 23 | 24 | app.use(function (req, res, next) { 25 | let err = new Error('This page not found'); 26 | err.status = 404; 27 | next(err) 28 | }); 29 | 30 | app.listen(3000, function () { 31 | console.log(`Server running in port ${config.port}`) 32 | }); 33 | -------------------------------------------------------------------------------- /server/controller/restaurant.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by lstfw on 2017/5/25. 3 | */ 4 | const express = require('express'); 5 | const model = require('../db/db.js'); 6 | const router = express.Router(); 7 | const moment = require('moment'); 8 | const objectIdToTimestamp = require('objectid-to-timestamp'); 9 | 10 | const _ = require('lodash'); 11 | 12 | const code_Ok = 200; 13 | const code_ERR = 600; 14 | 15 | // 注册 16 | const RestaurantInfo = (req, res) => { 17 | let RestaurantDataS = [ 18 | { 19 | restaurantName: '四海一家', 20 | restaurantPic: 'assets/img/shyj.jpg', 21 | distributionTime:'10', 22 | distance: '15KM', 23 | vacancy: '15', 24 | collect: 1, 25 | restaurantType: '新店入住', 26 | address: '深圳市南山区益田假日广场', 27 | telephone: '0755-85642365' 28 | },{ 29 | restaurantName: '屌丝烤鱼', 30 | restaurantPic: 'assets/img/shyj.jpg', 31 | distributionTime:'10', 32 | distance: '15KM', 33 | vacancy: '12', 34 | collect: 0, 35 | restaurantType: '新店入住', 36 | address: '深圳市宝安固戍二路', 37 | telephone: '0755-85642365' 38 | },{ 39 | restaurantName: '冠菌自助火锅', 40 | restaurantPic: 'assets/img/shyj.jpg', 41 | distributionTime:'10', 42 | distance: '15KM', 43 | vacancy: '15', 44 | collect: 1, 45 | restaurantType: '新店入住', 46 | address: '深圳市南山区益田假日广场', 47 | telephone: '0755-85642365' 48 | },{ 49 | restaurantName: '冠菌海鲜自助火锅', 50 | restaurantPic: 'assets/img/shyj.jpg', 51 | distributionTime:'10', 52 | distance: '15KM', 53 | vacancy: '15', 54 | collect: 1, 55 | restaurantType: '新店入住', 56 | address: '深圳市南山区益田假日广场', 57 | telephone: '0755-85642365' 58 | },{ 59 | restaurantName: '美味园', 60 | restaurantPic: 'assets/img/shyj.jpg', 61 | distributionTime:'10', 62 | distance: '15KM', 63 | vacancy: '15', 64 | collect: 1, 65 | restaurantType: '新店入住', 66 | address: '深圳市南山区益田假日广场', 67 | telephone: '0755-85642365' 68 | },{ 69 | restaurantName: '湖南蒸菜', 70 | restaurantPic: 'assets/img/shyj.jpg', 71 | distributionTime:'10', 72 | distance: '15KM', 73 | vacancy: '15', 74 | collect: 1, 75 | restaurantType: '新店入住', 76 | address: '深圳市南山区益田假日广场', 77 | telephone: '0755-85642365' 78 | },{ 79 | restaurantName: '湖南大碗菜', 80 | restaurantPic: 'assets/img/shyj.jpg', 81 | distributionTime:'10', 82 | distance: '15KM', 83 | vacancy: '15', 84 | collect: 1, 85 | restaurantType: '新店入住', 86 | address: '深圳市南山区益田假日广场', 87 | telephone: '0755-85642365' 88 | },{ 89 | restaurantName: '潮汕牛肉', 90 | restaurantPic: 'assets/img/shyj.jpg', 91 | distributionTime:'10', 92 | distance: '15KM', 93 | vacancy: '15', 94 | collect: 1, 95 | restaurantType: '新店入住', 96 | address: '深圳市南山区益田假日广场', 97 | telephone: '0755-85642365' 98 | } 99 | ]; 100 | for (let i = 0; i < RestaurantDataS.length; i++){ 101 | let RestaurantData = new model.Restaurant(RestaurantDataS[i]); 102 | console.log(RestaurantData); 103 | // 将 objectid 转换为 商户创建时间 104 | RestaurantData.create_time = moment(objectIdToTimestamp(RestaurantData._id)); 105 | model.Restaurant.findOne({userName: (RestaurantData.restaurantName).toLowerCase()}, (err, doc) => { 106 | RestaurantData.save(err => { 107 | if(err) console.log(err) 108 | console.log('register success') 109 | }) 110 | }) 111 | } 112 | res.json({ 113 | code: code_Ok, 114 | msg: '添加成功', 115 | }) 116 | 117 | }; 118 | 119 | // 所有用户打印 120 | const GetRestaurant = (req, res) => { 121 | model.Restaurant.find({}, (err, doc) => { 122 | if(err) console.log(err); 123 | if(doc.length == 0){ 124 | res.send({ 125 | code: code_ERR, 126 | msg: '附近没有餐厅' 127 | }) 128 | }else { 129 | res.send({ 130 | code: code_Ok, 131 | data: doc, 132 | msg: '用户信息获取成功' 133 | }) 134 | } 135 | }) 136 | }; 137 | 138 | 139 | module.exports = (router) => { 140 | router.post('/restaurantInfo', RestaurantInfo); 141 | router.post('/getRestaurant', GetRestaurant) 142 | }; 143 | -------------------------------------------------------------------------------- /server/controller/user.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const model = require('../db/db.js'); 3 | const router = express.Router(); 4 | const moment = require('moment'); 5 | const objectIdToTimestamp = require('objectid-to-timestamp'); 6 | const createToken = require('../middleware/createToken.js'); 7 | const checkToken = require('../middleware/checkToken.js'); 8 | const sha1 = require('sha1'); 9 | 10 | 11 | const code_Ok = 200; 12 | const code_ERR = 600; 13 | 14 | // 注册 15 | const Register = (req, res) => { 16 | let body = req.body; 17 | let userRegister = new model.User({ 18 | userName: body.userName, 19 | password: body.password, 20 | confirm_pwd: body.confirm_pwd, 21 | recheck: body.recheck, 22 | token: createToken(this.userName), 23 | head_pic: 'assets/img/dl.jpg', 24 | nickname: '逍遥随心', 25 | balance: '550', 26 | integral: '130', 27 | city: '深圳', 28 | }); 29 | // 将 objectid 转换为 用户创建时间 30 | userRegister.create_time = moment(objectIdToTimestamp(userRegister._id)); 31 | 32 | let reg = /(?!^[0-9]+$)(?!^[A-z]+$)(?!^[^A-z0-9]+$)^[^\s\u4e00-\u9fa5]{6,16}$/; 33 | if(!reg.test(userRegister.password)){ 34 | res.json({ 35 | code: code_ERR, 36 | msg: '密码长度需6-16位,且包含字母和字符', 37 | }) 38 | } else if(userRegister.password !== userRegister.confirm_pwd){ 39 | res.json({ 40 | code: code_ERR, 41 | msg: '两次输入密码不一致!', 42 | }) 43 | }else { 44 | model.User.findOne({userName: (userRegister.userName).toLowerCase()}, (err, doc) => { 45 | if(err) console.log(err); 46 | 47 | // 用户名已存在,不能注册 48 | if(doc) { 49 | res.json({ 50 | code: code_ERR, 51 | msg: '用户名已存在', 52 | }) 53 | } else { 54 | userRegister.password = sha1(userRegister.password); 55 | userRegister.confirm_pwd = sha1(userRegister.confirm_pwd); 56 | userRegister.save(err => { 57 | if(err) console.log(err); 58 | res.json({ 59 | code: code_Ok, 60 | msg: '注册成功', 61 | }) 62 | }) 63 | } 64 | }) 65 | } 66 | 67 | }; 68 | 69 | // 登录 70 | const Login = (req, res) => { 71 | let userLogin = new model.User({ 72 | userName: req.body.userName, 73 | password: sha1(req.body.password), 74 | token: createToken(this.userName) 75 | }); 76 | model.User.findOne({ userName: userLogin.userName }, (err, doc) => { 77 | if(err) console.log(err); 78 | if(!doc) { 79 | res.json({ 80 | code: code_ERR, 81 | msg: '账号不存在,立即去注册?' 82 | }) 83 | } else if(userLogin.password === doc.password) { 84 | let userName = req.body.userName; 85 | res.json({ 86 | code: code_Ok, 87 | userName: doc.userName, 88 | // 账户创建日期 89 | time: moment(objectIdToTimestamp(doc._id)).format('YYYY-MM-DD HH:mm:ss'), 90 | // token 信息验证 91 | token: createToken(userName) 92 | }) 93 | } else { 94 | res.json({ 95 | code: code_ERR, 96 | msg: '密码错误' 97 | }) 98 | } 99 | }) 100 | }; 101 | 102 | // 所有用户打印 103 | const User = (req, res) => { 104 | model.User.find({}, (err, doc) => { 105 | if(err) console.log(err); 106 | if(doc.length === 0){ 107 | res.send({ 108 | code: code_ERR, 109 | msg: '没有该用户信息' 110 | }) 111 | }else { 112 | res.send({ 113 | code: code_Ok, 114 | data: doc, 115 | msg: '用户信息获取成功' 116 | }) 117 | } 118 | }) 119 | }; 120 | 121 | // 获取用户信息 122 | const userInfo = (req, res) => { 123 | let token = JSON.stringify(req.body); 124 | model.User.find(token, (err, doc) => { 125 | if(err) console.log(err); 126 | if(doc.length === 0){ 127 | res.send({ 128 | code: code_ERR, 129 | msg: '没有找到该用户信息' 130 | }) 131 | }else { 132 | let data = doc[0]; 133 | let delAttr = ['password','confirm_pwd','create_time','token','userName','__v']; 134 | for (let i = 0; i < delAttr.length; i++){ 135 | let attr = delAttr[i]; 136 | data[attr] = undefined; 137 | } 138 | res.send({ 139 | code: code_Ok, 140 | data: data, 141 | msg: '用户信息获取成功' 142 | }) 143 | } 144 | }) 145 | }; 146 | 147 | // 更新用户头像 148 | const updateHeadPic = (req, res) => { 149 | let token = JSON.stringify(req.body); 150 | let update = {$set : {head_pic : req.body.head_pic}}; 151 | let options = {upsert : true}; 152 | model.User.update(token,update,options, (err, doc) => { 153 | if(err) console.log(err); 154 | if(doc.length === 0){ 155 | res.send({ 156 | code: code_ERR, 157 | msg: '没有找到该用户信息' 158 | }) 159 | }else { 160 | res.send({ 161 | code: code_Ok, 162 | msg: '头像修改成功' 163 | }) 164 | } 165 | }) 166 | }; 167 | 168 | // 删除用户 169 | const delUser = (req, res) => { 170 | model.User.findOneAndRemove({ _id: req.body.id }, err => { 171 | if(err) console.log(err); 172 | res.json({ 173 | success: true 174 | }) 175 | }) 176 | }; 177 | 178 | 179 | 180 | 181 | module.exports = (router) => { 182 | router.post('/register', Register), 183 | router.post('/login', Login), 184 | router.get('/user', checkToken, User), 185 | router.post('/delUser', checkToken, delUser), 186 | router.post('/userInfo', checkToken, userInfo), 187 | router.post('/update_head_pic', checkToken, updateHeadPic) 188 | }; 189 | -------------------------------------------------------------------------------- /server/db/db.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | const config = require('config-lite')(__dirname) 3 | 4 | // mongodb 连接🔗 5 | mongoose.connect(config.mongodb) 6 | // 此处防止 node.js - Mongoose: mpromise 错误 7 | mongoose.Promise = global.Promise; 8 | let db = mongoose.connection; 9 | db.on('error', console.error.bind(console, 'Connect error')) 10 | db.once('open', function () { 11 | console.log('MongoDB启动成功') 12 | }); 13 | 14 | 15 | let userSchema = mongoose.Schema({ 16 | userName: String, 17 | password: String, 18 | confirm_pwd:String, 19 | recheck: String, 20 | token: String, 21 | head_pic: String, 22 | nickname: String, 23 | balance: String, 24 | integral: String, 25 | city: String, 26 | create_time: Date 27 | }); 28 | 29 | let restaurantSchema = mongoose.Schema({ 30 | restaurantName: String, 31 | restaurantPic: String, 32 | distributionTime:String, 33 | distance: String, 34 | vacancy: String, 35 | collect: Number, 36 | restaurantType: String, 37 | address: String, 38 | telephone: String, 39 | create_time: Date 40 | }); 41 | 42 | let model = { 43 | // 在此处扩展 model,例如: 44 | // Article: mongoose.model('Article', articleSchema), 45 | User: mongoose.model('User', userSchema), 46 | Restaurant: mongoose.model('Restaurant', restaurantSchema) 47 | }; 48 | 49 | module.exports = model; 50 | -------------------------------------------------------------------------------- /server/middleware/checkToken.js: -------------------------------------------------------------------------------- 1 | // 监测 token 是否过期 2 | const jwt = require('jsonwebtoken') 3 | module.exports = function (req, res, next) { 4 | // console.log(req.headers) 5 | let token = req.headers['authorization'].split(' ')[1] 6 | // 解构 token,生成一个对象 { name: xx, iat: xx, exp: xx } 7 | let decoded = jwt.decode(token, 'secret') 8 | //console.log(decoded.exp) 9 | //console.log(Date.now() / 1000) 10 | // 监测 token 是否过期 11 | if(token && decoded.exp <= Date.now() / 1000) { 12 | return res.json({ 13 | code: 401, 14 | msg: '长时间未操作,请重新登录' 15 | }) 16 | } 17 | next(); 18 | } 19 | -------------------------------------------------------------------------------- /server/middleware/createToken.js: -------------------------------------------------------------------------------- 1 | // 创建 token 2 | // token 单点登录具体理解: http://www.tuicool.com/articles/uuAzAbU 3 | var jwt = require('jsonwebtoken') 4 | 5 | module.exports = function (name) { 6 | // 为方便测试,有效期设置为 10s 进行监测,普通生产情况下可以设置为更长的时间 7 | const token = jwt.sign({ 8 | name: name 9 | }, 'secret', { expiresIn: '3000s' }); 10 | return token; 11 | } 12 | -------------------------------------------------------------------------------- /server/routes/routes.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const UserController = require('../controller/user.js') 3 | const RestaurantController = require('../controller/restaurant.js') 4 | const router = express.Router() 5 | 6 | UserController(router); 7 | RestaurantController(router); 8 | 9 | module.exports = router 10 | -------------------------------------------------------------------------------- /src/API/axios.js: -------------------------------------------------------------------------------- 1 | import $http from 'axios' 2 | import router from '@/router' 3 | import store from '@/store' 4 | 5 | import {Indicator} from 'mint-ui'; 6 | import { Toast } from 'mint-ui'; 7 | 8 | 9 | $http.default.timeout = 5000; 10 | $http.defaults.headers.post['Content-Type'] = 'application/json'; 11 | 12 | const instance = $http.create(); 13 | instance.defaults.headers.post['Content-Type'] = 'application/json'; 14 | 15 | $http.interceptors.request.use = instance.interceptors.request.use; 16 | 17 | 18 | instance.interceptors.request.use(config => { 19 | Indicator.open({ 20 | spinnerType: 'fading-circle' 21 | }); 22 | 23 | if (localStorage.getItem('token')) { 24 | config.headers.Authorization = `token ${localStorage.getItem('token')}`.replace(/(^\")|(\"$)/g, '') 25 | } 26 | return config 27 | }, err => { 28 | Indicator.open({ 29 | spinnerType: 'fading-circle' 30 | }); 31 | return Promise.reject(err) 32 | }); 33 | 34 | 35 | // axios拦截响应 36 | instance.interceptors.response.use(response => { 37 | Indicator.close(); 38 | if (response) { 39 | } 40 | switch (response.data.code) { 41 | case 401: 42 | // 401 清除token信息并跳转到登录页面 43 | store.commit('delToken', null) 44 | router.replace({ 45 | path: '/', 46 | query: {redirect: router.currentRoute.fullPath} 47 | }) 48 | } 49 | return response 50 | }, err => { 51 | Indicator.close(); 52 | Toast('网络太差,请稍后再试'); 53 | return Promise.reject(err) 54 | }); 55 | 56 | export default { 57 | // 用户注册 58 | userRegister(data) { 59 | return instance.post('/api/register', data) 60 | }, 61 | // 用户登录 62 | userLogin(data) { 63 | return instance.post('/api/login', data) 64 | }, 65 | // 获取用户 66 | getUser() { 67 | return instance.get('/api/user') 68 | }, 69 | // 获取用户信息 70 | getUserInfo(data) { 71 | return instance.post('/api/userInfo', data) 72 | }, 73 | // 获取用户信息 74 | updateHeadPic(data) { 75 | return instance.post('/api/update_head_pic', data) 76 | }, 77 | // 删除用户 78 | delUser(data) { 79 | return instance.post('/api/delUser', data) 80 | }, 81 | // 添加商户信息 82 | addRestaurantInfo(data) { 83 | return instance.post('/api/restaurantInfo', data) 84 | }, 85 | // 获取商户信息 86 | getRestaurantInfo(data) { 87 | return instance.post('/api/getRestaurant', data) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/assets/css/icon.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'icomoon'; 3 | src: url('../fonts/icomoon.eot?et96xx'); 4 | src: url('../fonts/icomoon.eot?et96xx#iefix') format('embedded-opentype'), 5 | url('../fonts/icomoon.ttf?et96xx') format('truetype'), 6 | url('../fonts/icomoon.woff?et96xx') format('woff'), 7 | url('../fonts/icomoon.svg?et96xx#icomoon') format('svg'); 8 | font-weight: normal; 9 | font-style: normal; 10 | } 11 | 12 | [class^="icon-"], [class*=" icon-"] { 13 | /* use !important to prevent issues with browser extensions that change fonts */ 14 | font-family: 'icomoon' !important; 15 | speak: none; 16 | font-style: normal; 17 | font-weight: normal; 18 | font-variant: normal; 19 | text-transform: none; 20 | line-height: 1; 21 | 22 | /* Better Font Rendering =========== */ 23 | -webkit-font-smoothing: antialiased; 24 | -moz-osx-font-smoothing: grayscale; 25 | } 26 | 27 | .icon-file-text2:before { 28 | content: "\e926"; 29 | } 30 | .icon-cart:before { 31 | content: "\e93a"; 32 | } 33 | .icon-coin-dollar:before { 34 | content: "\e93b"; 35 | } 36 | .icon-coin-yen:before { 37 | content: "\e93e"; 38 | } 39 | .icon-location:before { 40 | content: "\e947"; 41 | } 42 | .icon-calendar:before { 43 | content: "\e953"; 44 | } 45 | .icon-spoon-knife:before { 46 | content: "\e9a3"; 47 | } 48 | .icon-airplane:before { 49 | content: "\e9af"; 50 | } 51 | .icon-truck:before { 52 | content: "\e9b0"; 53 | } 54 | .icon-heart:before { 55 | content: "\e9da"; 56 | } 57 | .icon-plus:before { 58 | content: "\ea0a"; 59 | } 60 | .icon-minus:before { 61 | content: "\ea0b"; 62 | } 63 | .icon-checkmark:before { 64 | content: "\ea10"; 65 | } 66 | .icon-ctrl:before { 67 | content: "\ea50"; 68 | } 69 | .icon-file-openoffice:before { 70 | content: "\eae0"; 71 | } 72 | .icon-libreoffice:before { 73 | content: "\eae3"; 74 | } 75 | .icon-IcoMoon:before { 76 | content: "\eaea"; 77 | } 78 | -------------------------------------------------------------------------------- /src/assets/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 | /*工具样式*/ 33 | .clearFloat:after { 34 | display: block; 35 | clear: both; 36 | content: ""; 37 | visibility: hidden; 38 | height: 0 39 | } 40 | #app{ 41 | max-width: 720px; 42 | margin: 0 auto; 43 | } 44 | body { 45 | line-height: 1; 46 | } 47 | 48 | blockquote, q { 49 | quotes: none; 50 | } 51 | 52 | blockquote:before, blockquote:after, 53 | q:before, q:after { 54 | content: none; 55 | } 56 | 57 | table { 58 | border-collapse: collapse; 59 | border-spacing: 0; 60 | } 61 | 62 | /* custom */ 63 | a { 64 | color: #7e8c8d; 65 | text-decoration: none; 66 | -webkit-backface-visibility: hidden; 67 | } 68 | 69 | li { 70 | list-style: none; 71 | } 72 | 73 | ::-webkit-scrollbar { 74 | width: 5px; 75 | height: 5px; 76 | } 77 | 78 | ::-webkit-scrollbar-track-piece { 79 | background-color: rgba(0, 0, 0, 0.2); 80 | -webkit-border-radius: 6px; 81 | } 82 | 83 | ::-webkit-scrollbar-thumb:vertical { 84 | height: 5px; 85 | background-color: rgba(125, 125, 125, 0.7); 86 | -webkit-border-radius: 6px; 87 | } 88 | 89 | ::-webkit-scrollbar-thumb:horizontal { 90 | width: 5px; 91 | background-color: rgba(125, 125, 125, 0.7); 92 | -webkit-border-radius: 6px; 93 | } 94 | 95 | html, body { 96 | width: 100%; 97 | } 98 | 99 | body { 100 | -webkit-text-size-adjust: none; 101 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 102 | } 103 | 104 | 105 | -------------------------------------------------------------------------------- /src/assets/fonts/icomoon.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fwlst/vue-fast/53c58cf5f9a54099b4ab60af00c41eb30e8a3d6b/src/assets/fonts/icomoon.eot -------------------------------------------------------------------------------- /src/assets/fonts/icomoon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Generated by IcoMoon 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/assets/fonts/icomoon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fwlst/vue-fast/53c58cf5f9a54099b4ab60af00c41eb30e8a3d6b/src/assets/fonts/icomoon.ttf -------------------------------------------------------------------------------- /src/assets/fonts/icomoon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fwlst/vue-fast/53c58cf5f9a54099b4ab60af00c41eb30e8a3d6b/src/assets/fonts/icomoon.woff -------------------------------------------------------------------------------- /src/assets/img/dl.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fwlst/vue-fast/53c58cf5f9a54099b4ab60af00c41eb30e8a3d6b/src/assets/img/dl.jpg -------------------------------------------------------------------------------- /src/assets/img/err.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fwlst/vue-fast/53c58cf5f9a54099b4ab60af00c41eb30e8a3d6b/src/assets/img/err.jpg -------------------------------------------------------------------------------- /src/assets/img/shyj.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fwlst/vue-fast/53c58cf5f9a54099b4ab60af00c41eb30e8a3d6b/src/assets/img/shyj.jpg -------------------------------------------------------------------------------- /src/components/index/header.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 230 | 231 | 232 | 293 | -------------------------------------------------------------------------------- /src/components/index/restaurantList.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 75 | 76 | 77 | 183 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | // The Vue build version to load with the `import` command 2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 3 | import Vue from 'vue' 4 | import router from './router' 5 | import $http from 'axios'; 6 | 7 | /* reset import 全局引入重置样式 */ 8 | import '@/assets/css/reset.css'; 9 | import '@/assets/css/icon.css'; 10 | 11 | /*引入 store*/ 12 | import store from '@/store' 13 | 14 | /*引入 注冊 mint-ui*/ 15 | import MintUI from 'mint-ui' 16 | import 'mint-ui/lib/style.css' 17 | Vue.use(MintUI); 18 | 19 | /*引入注册表单验证组件*/ 20 | import Vuelidate from 'vuelidate' 21 | Vue.use(Vuelidate) 22 | 23 | //登陆拦截 24 | router.beforeEach((to, from, next) => { 25 | if (to.meta.requireAuth) { // 判断该路由是否需要登录权限 26 | if (store.state.login.token) { // 通过vuex state获取当前的token是否存在 27 | next(); 28 | } else { 29 | next({ 30 | path: '/', 31 | query: {redirect: to.fullPath} // 将跳转的路由path作为参数,登录成功后跳转到该路由 32 | }) 33 | } 34 | } else { 35 | next(); 36 | } 37 | }) 38 | 39 | 40 | Vue.prototype.$http = $http; 41 | 42 | Vue.config.productionTip = false; 43 | 44 | /* eslint-disable no-new */ 45 | new Vue({ 46 | el: '#app', 47 | router, 48 | store, 49 | //template: '', 50 | //components: { App } 51 | }); 52 | -------------------------------------------------------------------------------- /src/page/err.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 23 | 24 | 25 | 47 | -------------------------------------------------------------------------------- /src/page/index.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 49 | 50 | 51 | 76 | -------------------------------------------------------------------------------- /src/page/login.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 67 | 68 | 69 | 94 | -------------------------------------------------------------------------------- /src/page/register.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 75 | 76 | 77 | 102 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | 4 | 5 | import Login from '../page/login' 6 | import Register from '../page/register' 7 | import Index from '../page/index' 8 | import Err from '../page/err' 9 | 10 | Vue.use(Router); 11 | 12 | export default new Router({ 13 | mode: 'history', 14 | routes: [ 15 | { 16 | path: '/', 17 | name: 'Login', 18 | component: Login 19 | }, { 20 | path: '/register', 21 | name: 'Register', 22 | component: Register 23 | }, { 24 | path: '/index', 25 | name: 'Index', 26 | component: Index, 27 | meta: { 28 | requireAuth: true, // 添加该字段,表示进入这个路由是需要登录的 29 | }, 30 | }, { 31 | path: '/*', 32 | name: 'Err', 33 | component: Err 34 | } 35 | ] 36 | }) 37 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by lstfw on 2017/4/24. 3 | */ 4 | import Vuex from 'vuex' 5 | import Vue from 'vue' 6 | 7 | import login from '@/store/modules/login' 8 | 9 | Vue.use(Vuex); 10 | 11 | export default new Vuex.Store({ 12 | modules:{ 13 | login 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /src/store/modules/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by lstfw on 2017/4/24. 3 | */ 4 | import $http from 'axios'; 5 | /*状态码*/ 6 | const OK_code = 200; 7 | 8 | 9 | /*声明数据*/ 10 | const state = { 11 | indexPostData: { 12 | activityId: '81b6e88c-17e2-478a-9a2d-0024fdbf3b19', 13 | openid: '' 14 | }, 15 | activityData: {} 16 | }; 17 | 18 | /*同步更新store*/ 19 | const mutations = { 20 | updatePostData (state,{key,val}){ 21 | state.indexPostData[key] = val; 22 | }, 23 | updateActivityData (state,payload){ 24 | state.activityData = payload; 25 | }, 26 | }; 27 | 28 | /*异步更新store*/ 29 | const actions = { 30 | fatchActivityData ({commit,state}){ 31 | return new Promise((resolve,reject) => { 32 | $http.post('/activity', state.indexPostData).then((res) => { 33 | if(res.data.code == OK_code){ 34 | let data = res.data.data; 35 | let activityNewData = {}; 36 | activityNewData.activityStatus = data.activityStatus; 37 | activityNewData.orderPayment = data.orderPayment; 38 | activityNewData.remark = data.remark; 39 | activityNewData.titlePic = data.titlePic; 40 | activityNewData.itemData = []; 41 | let key = ['参与人数','目标人数','进度','参与时间']; 42 | let val = [data.registerNum,data.targetCount,data.progressNum + '%',data.remainingTime]; 43 | key.forEach(function (v,i) { 44 | let itemDataObj = { 45 | title: key[i], 46 | val: val[i] 47 | }; 48 | activityNewData.itemData.push(itemDataObj); 49 | }); 50 | commit('updateActivityData',activityNewData); 51 | resolve(activityNewData); 52 | }else { 53 | reject(res.data); 54 | } 55 | }, (err) => { 56 | 57 | }) 58 | }); 59 | 60 | } 61 | }; 62 | 63 | /**/ 64 | const getters = { 65 | getPostData: state => state.indexPostData, 66 | getActivityData: state => state.activityData 67 | }; 68 | export default { 69 | state, 70 | mutations, 71 | actions, 72 | getters 73 | } 74 | -------------------------------------------------------------------------------- /src/store/modules/login.js: -------------------------------------------------------------------------------- 1 | /*声明数据*/ 2 | const state = { 3 | token: localStorage.getItem('token') 4 | }; 5 | 6 | /*同步更新store*/ 7 | const mutations = { 8 | updateToken (state,payload){ 9 | localStorage.setItem('token',payload); 10 | state.token = payload; 11 | }, 12 | delToken (state,payload){ 13 | localStorage.removeItem('token'); 14 | state.token = payload; 15 | }, 16 | }; 17 | 18 | /*异步更新store*/ 19 | const actions = { 20 | setToken ({commit,state}){ 21 | 22 | } 23 | }; 24 | 25 | export default { 26 | state, 27 | mutations, 28 | } 29 | -------------------------------------------------------------------------------- /static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fwlst/vue-fast/53c58cf5f9a54099b4ab60af00c41eb30e8a3d6b/static/.gitkeep -------------------------------------------------------------------------------- /static/img/dl.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fwlst/vue-fast/53c58cf5f9a54099b4ab60af00c41eb30e8a3d6b/static/img/dl.jpg -------------------------------------------------------------------------------- /static/img/shyj.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fwlst/vue-fast/53c58cf5f9a54099b4ab60af00c41eb30e8a3d6b/static/img/shyj.jpg --------------------------------------------------------------------------------