├── README.md ├── vue2.x-koa2.x ├── .gitignore ├── config │ ├── prod.env.js │ ├── dev.env.js │ └── index.js ├── src │ ├── components │ │ ├── main.vue │ │ ├── error │ │ │ └── notFound.vue │ │ ├── asideContainer │ │ │ ├── goods.vue │ │ │ └── platform.vue │ │ ├── container │ │ │ ├── userHome.vue │ │ │ ├── container.vue │ │ │ └── header.vue │ │ ├── common │ │ │ └── treeMenu.vue │ │ ├── platform │ │ │ ├── userList.vue │ │ │ └── rightsManagement.vue │ │ ├── login │ │ │ └── login.vue │ │ └── goods │ │ │ ├── list.vue │ │ │ └── management.vue │ ├── assets │ │ └── img │ │ │ ├── file.png │ │ │ ├── logo.png │ │ │ ├── folder.png │ │ │ ├── file-text.png │ │ │ └── folder-open.png │ ├── main.js │ └── routes.js ├── .editorconfig ├── .babelrc ├── server │ ├── routes │ │ ├── image.js │ │ ├── user.js │ │ └── goods.js │ ├── config │ │ └── db.js │ ├── controllers │ │ ├── image.js │ │ ├── user.js │ │ ├── goods.js │ │ └── common │ │ │ └── file.js │ ├── schema │ │ ├── user.js │ │ └── goods.js │ ├── models │ │ ├── user.js │ │ └── goods.js │ └── start.js ├── build │ ├── dev-client.js │ ├── build.js │ ├── check-versions.js │ ├── webpack.dev.conf.js │ ├── utils.js │ ├── dev-server.js │ ├── webpack.base.conf.js │ └── webpack.prod.conf.js ├── README.md ├── index.html ├── sql │ └── my_test_db.sql └── package.json └── tree-menu ├── .gitignore ├── .babelrc ├── src ├── assets │ ├── file.png │ ├── folder.png │ ├── loading.gif │ ├── file-text.png │ └── folder-open.png ├── main.js └── components │ ├── common │ └── treeMenu.vue │ └── main.vue ├── index.html ├── package.json └── webpack.config.js /README.md: -------------------------------------------------------------------------------- 1 | # Vue2.x demos 2 | 3 | > Vue.js 的学习与练习 4 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log 5 | -------------------------------------------------------------------------------- /tree-menu/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log 5 | .idea 6 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/config/prod.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: '"production"' 3 | } 4 | -------------------------------------------------------------------------------- /tree-menu/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["es2015", { "modules": false }] 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/src/components/main.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/src/components/error/notFound.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /tree-menu/src/assets/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caihg/vue-demos/HEAD/tree-menu/src/assets/file.png -------------------------------------------------------------------------------- /tree-menu/src/assets/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caihg/vue-demos/HEAD/tree-menu/src/assets/folder.png -------------------------------------------------------------------------------- /tree-menu/src/assets/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caihg/vue-demos/HEAD/tree-menu/src/assets/loading.gif -------------------------------------------------------------------------------- /tree-menu/src/assets/file-text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caihg/vue-demos/HEAD/tree-menu/src/assets/file-text.png -------------------------------------------------------------------------------- /tree-menu/src/assets/folder-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caihg/vue-demos/HEAD/tree-menu/src/assets/folder-open.png -------------------------------------------------------------------------------- /vue2.x-koa2.x/src/assets/img/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caihg/vue-demos/HEAD/vue2.x-koa2.x/src/assets/img/file.png -------------------------------------------------------------------------------- /vue2.x-koa2.x/src/assets/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caihg/vue-demos/HEAD/vue2.x-koa2.x/src/assets/img/logo.png -------------------------------------------------------------------------------- /vue2.x-koa2.x/src/assets/img/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caihg/vue-demos/HEAD/vue2.x-koa2.x/src/assets/img/folder.png -------------------------------------------------------------------------------- /vue2.x-koa2.x/src/assets/img/file-text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caihg/vue-demos/HEAD/vue2.x-koa2.x/src/assets/img/file-text.png -------------------------------------------------------------------------------- /vue2.x-koa2.x/src/assets/img/folder-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caihg/vue-demos/HEAD/vue2.x-koa2.x/src/assets/img/folder-open.png -------------------------------------------------------------------------------- /tree-menu/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import main from './components/main.vue' 3 | 4 | new Vue({ 5 | el: '#app', 6 | render: h => h(main) 7 | }) 8 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/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 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/.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 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-0"], 3 | "plugins": ["transform-runtime"], 4 | "comments": false, 5 | "env": { 6 | "test": { 7 | "plugins": [ "istanbul" ] 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/server/routes/image.js: -------------------------------------------------------------------------------- 1 | const imgController = require('../controllers/image.js'); 2 | const router = require('koa-router')(); 3 | 4 | router.post('/uploads/img', imgController.uploadImg) 5 | 6 | module.exports = router; 7 | -------------------------------------------------------------------------------- /tree-menu/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue.js 递归组件实现树形菜单 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/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 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/server/config/db.js: -------------------------------------------------------------------------------- 1 | const Sequelize = require('sequelize'); 2 | 3 | // 使用 url 形式连接数据库 4 | const theDb = new Sequelize('mysql://root:123456@localhost/my_test_db', { 5 | define: { 6 | timestamps: false // 取消Sequelzie自动给数据表添加的 createdAt 和 updatedAt 两个时间戳字段 7 | } 8 | }) 9 | 10 | module.exports = { 11 | theDb 12 | } 13 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/server/routes/user.js: -------------------------------------------------------------------------------- 1 | const userController = require('../controllers/user.js'); 2 | const router = require('koa-router')(); 3 | 4 | router 5 | .post('/user', userController.postUserAuth) 6 | .get('/user/:id', userController.getUserInfo) // 定义 url 的参数 id 7 | .get('/user/list', userController.getUserList) 8 | 9 | module.exports = router; 10 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/README.md: -------------------------------------------------------------------------------- 1 | # vue2.x-koa2.x 2 | 3 | > Vue.js 与 Koa.js 的练习项目:一个基础的后台管理系统 4 | 5 | ## 步骤 6 | 7 | ``` bash 8 | # 安装依赖 9 | npm install 10 | 11 | # 启动本地服务 localhost:8080 12 | npm run dev 13 | 14 | # 用于生产环境的构建 15 | npm run build 16 | ``` 17 | 18 | 相关参考 [vuejs-templates](http://vuejs-templates.github.io/webpack/) [vue-loader](http://vuejs.github.io/vue-loader). 19 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/src/components/asideContainer/goods.vue: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Management System with Vue2.x and Koa1.x 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/server/routes/goods.js: -------------------------------------------------------------------------------- 1 | const goodsController = require('../controllers/goods.js'); 2 | const router = require('koa-router')(); 3 | 4 | router.post('/goods/list', goodsController.getGoodsList); 5 | router.get('/goods/:id', goodsController.getGoodsDetails); 6 | router.delete('/goods/:id/', goodsController.removeGoods); 7 | router.post('/goods/management', goodsController.manageGoods); 8 | 9 | module.exports = router; 10 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/server/controllers/image.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const uploadFile = require('./common/file.js').uploadFile; 3 | 4 | const uploadImg = async function() { 5 | const serverFilePath = path.join( __dirname, '../../uploads' ) 6 | 7 | result = await uploadFile(this, { 8 | dir: 'album', 9 | path: serverFilePath 10 | }); 11 | 12 | this.body = result; 13 | } 14 | 15 | module.exports = { 16 | uploadImg 17 | } 18 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/src/components/container/userHome.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 22 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/src/components/container/container.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 17 | 18 | 27 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/server/schema/user.js: -------------------------------------------------------------------------------- 1 | /* jshint indent: 2 */ 2 | 3 | module.exports = function(sequelize, DataTypes) { 4 | return sequelize.define('user', { 5 | id: { 6 | type: DataTypes.INTEGER(11), 7 | allowNull: false, 8 | primaryKey: true, 9 | autoIncrement: true 10 | }, 11 | user_name: { 12 | type: DataTypes.CHAR(50), 13 | allowNull: false 14 | }, 15 | password: { 16 | type: DataTypes.CHAR(128), 17 | allowNull: false 18 | } 19 | }, { 20 | tableName: 'user' 21 | }); 22 | }; 23 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/server/schema/goods.js: -------------------------------------------------------------------------------- 1 | /* jshint indent: 2 */ 2 | 3 | module.exports = function(sequelize, DataTypes) { 4 | return sequelize.define('goods', { 5 | id: { 6 | type: DataTypes.INTEGER(11), 7 | allowNull: false, 8 | primaryKey: true, 9 | autoIncrement: true 10 | }, 11 | name: { 12 | type: DataTypes.CHAR(50), 13 | allowNull: false 14 | }, 15 | description: { 16 | type: DataTypes.CHAR(200), 17 | allowNull: true 18 | }, 19 | img_url: { 20 | type: DataTypes.STRING, 21 | allowNull: true 22 | } 23 | }, { 24 | tableName: 'goods' 25 | }); 26 | }; 27 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/server/models/user.js: -------------------------------------------------------------------------------- 1 | const theDatabase = require('../config/db.js').theDb; 2 | const userSchema = theDatabase.import('../schema/user.js'); 3 | 4 | // 通过用户名查找 5 | const getUserByName = async function(name) { 6 | const userInfo = await userSchema.findOne({ 7 | where: { 8 | user_name: name 9 | } 10 | }) 11 | 12 | return userInfo 13 | } 14 | 15 | // 通过用户 id 查找 16 | const getUserById = async function(id) { 17 | const userInfo = await userSchema.findOne({ 18 | where: { 19 | id: id 20 | } 21 | }); 22 | 23 | return userInfo 24 | } 25 | 26 | const getUserList = async function() { 27 | return await userSchema.findAndCount(); // findAndCount() 用 get 路由访问,会得到 204 状态:无数据返回。改用 post 就行 28 | } 29 | 30 | module.exports = { 31 | getUserByName, 32 | getUserById, 33 | getUserList 34 | } 35 | -------------------------------------------------------------------------------- /tree-menu/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tree-menu", 3 | "description": "树形菜单", 4 | "version": "0.0.1", 5 | "author": "caihg", 6 | "private": false, 7 | "scripts": { 8 | "dev": "cross-env NODE_ENV=development webpack-dev-server --inline --hot --open", 9 | "build": "cross-env NODE_ENV=production webpack --progress --hide-modules" 10 | }, 11 | "dependencies": { 12 | "vue": "^2.5.16" 13 | }, 14 | "devDependencies": { 15 | "babel-core": "^6.26.0", 16 | "babel-loader": "^7.1.4", 17 | "babel-preset-es2015": "^6.24.1", 18 | "cross-env": "^5.1.4", 19 | "css-loader": "^0.28.11", 20 | "file-loader": "^1.1.11", 21 | "style-loader": "^0.20.3", 22 | "vue-loader": "^14.2.2", 23 | "vue-template-compiler": "^2.5.16", 24 | "webpack": "^3.11.0", 25 | "webpack-dev-middleware": "^3.1.2", 26 | "webpack-dev-server": "^2.11.2" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/src/components/asideContainer/platform.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 36 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/build/build.js: -------------------------------------------------------------------------------- 1 | // https://github.com/shelljs/shelljs 2 | require('./check-versions')() 3 | require('shelljs/global') 4 | env.NODE_ENV = 'production' 5 | 6 | var path = require('path') 7 | var config = require('../config') 8 | var ora = require('ora') 9 | var webpack = require('webpack') 10 | var webpackConfig = require('./webpack.prod.conf') 11 | 12 | console.log( 13 | ' Tip:\n' + 14 | ' Built files are meant to be served over an HTTP server.\n' + 15 | ' Opening index.html over file:// won\'t work.\n' 16 | ) 17 | 18 | var spinner = ora('building for production...') 19 | spinner.start() 20 | 21 | var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory) 22 | rm('-rf', assetsPath) 23 | mkdir('-p', assetsPath) 24 | cp('-R', 'static/*', assetsPath) 25 | 26 | webpack(webpackConfig, function (err, stats) { 27 | spinner.stop() 28 | if (err) throw err 29 | process.stdout.write(stats.toString({ 30 | colors: true, 31 | modules: false, 32 | children: false, 33 | chunks: false, 34 | chunkModules: false 35 | }) + '\n') 36 | }) 37 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/build/check-versions.js: -------------------------------------------------------------------------------- 1 | var semver = require('semver') 2 | var chalk = require('chalk') 3 | var packageConfig = require('../package.json') 4 | var exec = function (cmd) { 5 | return require('child_process') 6 | .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 | name: 'npm', 17 | currentVersion: exec('npm --version'), 18 | versionRequirement: packageConfig.engines.npm 19 | } 20 | ] 21 | 22 | module.exports = function () { 23 | var warnings = [] 24 | for (var i = 0; i < versionRequirements.length; i++) { 25 | var mod = versionRequirements[i] 26 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 27 | warnings.push(mod.name + ': ' + 28 | chalk.red(mod.currentVersion) + ' should be ' + 29 | chalk.green(mod.versionRequirement) 30 | ) 31 | } 32 | } 33 | 34 | if (warnings.length) { 35 | console.log('') 36 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 37 | console.log() 38 | for (var i = 0; i < warnings.length; i++) { 39 | var warning = warnings[i] 40 | console.log(' ' + warning) 41 | } 42 | console.log() 43 | process.exit(1) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | var config = require('../config') 2 | var webpack = require('webpack') 3 | var merge = require('webpack-merge') 4 | var utils = require('./utils') 5 | var baseWebpackConfig = require('./webpack.base.conf') 6 | var HtmlWebpackPlugin = require('html-webpack-plugin') 7 | var FriendlyErrors = 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 | loaders: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) 17 | }, 18 | // eval-source-map is faster for development 19 | devtool: '#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.optimize.OccurrenceOrderPlugin(), 26 | new webpack.HotModuleReplacementPlugin(), 27 | new webpack.NoErrorsPlugin(), 28 | // https://github.com/ampedandwired/html-webpack-plugin 29 | new HtmlWebpackPlugin({ 30 | filename: 'index.html', 31 | template: 'index.html', 32 | inject: true 33 | }), 34 | new FriendlyErrors() 35 | ] 36 | }) 37 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/server/models/goods.js: -------------------------------------------------------------------------------- 1 | const theDatabase = require('../config/db.js').theDb; 2 | const goodsSchema = theDatabase.import('../schema/goods.js'); 3 | 4 | const getGoodsList = async (searchVal) => { 5 | return await goodsSchema.findAndCount( 6 | { 7 | where: { 8 | name: { 9 | $like: '%' + searchVal + '%' // searchVal:要搜索的商品名称 10 | } 11 | }, 12 | order: 'id desc' // 根据 id 倒序 13 | } 14 | ); 15 | } 16 | 17 | // 根据商品 id 查找数据 18 | const getGoodsDetails = async (id) => { 19 | return await goodsSchema.findById(id); 20 | } 21 | 22 | // 添加商品 23 | const addGoods = async (name, description, img_url) => { 24 | await goodsSchema.create({ 25 | name, 26 | description, 27 | img_url 28 | }); 29 | 30 | return true; 31 | } 32 | 33 | // 根据商品 id 修改 34 | const updateGoods = async (id, name, description, img_url) => { 35 | await goodsSchema.update( 36 | { 37 | name, 38 | description, 39 | img_url 40 | }, 41 | { 42 | where: { 43 | id 44 | } 45 | } 46 | ); 47 | 48 | return true; 49 | } 50 | 51 | // 根据商品 id 删除数据 52 | const removeGoods = async (id) => { 53 | await goodsSchema.destroy({ 54 | where: { 55 | id 56 | } 57 | }); 58 | 59 | return true; 60 | } 61 | 62 | module.exports = { 63 | getGoodsList, 64 | getGoodsDetails, 65 | addGoods, 66 | updateGoods, 67 | removeGoods 68 | } 69 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/src/components/common/treeMenu.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 38 | 39 | 57 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import ElementUI from 'element-ui' 3 | import 'element-ui/lib/theme-default/index.css' 4 | import VueRouter from 'vue-router' 5 | import Axios from 'axios' 6 | 7 | Vue.use(ElementUI); 8 | Vue.use(VueRouter); 9 | Vue.prototype.$http = Axios 10 | 11 | import routes from './routes' 12 | const router = new VueRouter({ 13 | mode: 'history', 14 | base: __dirname, 15 | routes: routes 16 | }) 17 | 18 | import jwt from 'jsonwebtoken' 19 | 20 | router.beforeEach((to, from, next) => { 21 | let token = localStorage.getItem('demo-token'); 22 | 23 | const decoded = token && jwt.verify(token, 'vue-koa-demo'); 24 | if (decoded) { 25 | if (decoded.originExp - Date.now() < 0) { // 已过期 26 | localStorage.removeItem('demo-token'); 27 | } else { 28 | decoded.originExp = Date.now() + 60 * 60 * 1000; 29 | token = jwt.sign(decoded, 'vue-koa-demo'); 30 | localStorage.setItem('demo-token', token); 31 | } 32 | } 33 | 34 | if (to.path == '/') { 35 | if (token) { 36 | next('/page/userHome') 37 | } 38 | next(); 39 | } else { 40 | if (token) { 41 | Vue.prototype.$http.defaults.headers.common['Authorization'] = 'Bearer ' + token; // 全局设定 header 的 token 验证 42 | next() 43 | } else { 44 | next('/') 45 | } 46 | } 47 | }) 48 | 49 | import Main from './components/main.vue' 50 | const app = new Vue({ 51 | router, 52 | render: h => h(Main) 53 | }).$mount('#app') 54 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/src/components/platform/userList.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 68 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/server/start.js: -------------------------------------------------------------------------------- 1 | const path = require('path'), 2 | koa = new (require('koa'))(), 3 | router = require('koa-router')(), 4 | bodyparser = require('koa-bodyparser'), // 对于 POST 请求,将 koa2 上下文的 formData 数据解析到 ctx.request.body 5 | logger = require('koa-logger'), // 日志中间件 6 | koaStatic = require('koa-static'), 7 | historyApiFallback = require('koa-history-api-fallback'), 8 | userRoute = require('./routes/user.js'), 9 | goodsRoute = require('./routes/goods.js'), 10 | imageRoute = require('./routes/image.js'); 11 | 12 | koa.use(bodyparser()); 13 | koa.use(logger()); 14 | koa.use(historyApiFallback()); 15 | 16 | /*koa.use(async (ctx, next) => { // ctx 封装了node 中的 request 和 response 17 | let start = new Date(); 18 | await next(); 19 | let ms = new Date - start; 20 | console.log('%s %s - %s 毫秒', ctx.method, ctx.url, ms); 21 | console.log('ctx.body 是 ctx.response.body 的简写', '=>', ctx.body === ctx.response.body); 22 | console.log('ctx.request.body 获取 post 请求中的参数', '=>', ctx.request.body); 23 | });*/ 24 | 25 | koa.on('error', function(err, ctx) { 26 | console.log('server error: ', err); 27 | }); 28 | 29 | // 静态文件服务 koa-static 规则位于 koa-router 的系列规则之前 30 | koa.use(koaStatic(path.resolve('dist'))); // 将 webpack 打包好的项目目录作为 Koa 静态文件服务的目录 31 | 32 | // 挂载到 koa-router 上,同时会让所有的 user 的请求路径前面加上 '/auth' 前缀。 33 | router.use('/auth', userRoute.routes()); 34 | 35 | router.use(goodsRoute.routes()); 36 | 37 | router.use(imageRoute.routes()); 38 | 39 | koa.use(router.routes()); // 将路由规则挂载到Koa上。 40 | 41 | koa.listen(9090, () => { 42 | console.log('Koa is listening on port 9090'); 43 | }); 44 | 45 | module.exports = koa; 46 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/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: false, 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 | }, 19 | dev: { 20 | env: require('./dev.env'), 21 | port: 8080, 22 | assetsSubDirectory: 'static', 23 | assetsPublicPath: '/', 24 | proxyTable: { 25 | '/auth': { 26 | target: 'http://localhost:9090', 27 | changeOrigin: true 28 | }, 29 | '/goods': { 30 | target: 'http://localhost:9090', 31 | changeOrigin: true 32 | }, 33 | '/uploads': { 34 | target: 'http://localhost:9090', 35 | changeOrigin: true 36 | } 37 | }, 38 | // CSS Sourcemaps off by default because relative paths are "buggy" 39 | // with this option, according to the CSS-Loader README 40 | // (https://github.com/webpack/css-loader#sourcemaps) 41 | // In our experience, they generally work as expected, 42 | // just be aware of this issue when enabling this option. 43 | cssSourceMap: false 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tree-menu/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | 4 | module.exports = { 5 | entry: './src/main.js', 6 | output: { 7 | path: path.resolve(__dirname, './dist'), 8 | publicPath: '/dist/', 9 | filename: 'build.js' 10 | }, 11 | resolve: { 12 | alias: { 13 | 'vue$': 'vue/dist/vue.js' 14 | } 15 | }, 16 | module: { 17 | loaders: [ 18 | { 19 | test: /\.vue$/, 20 | loader: 'vue-loader' 21 | }, 22 | { 23 | test: /\.js$/, 24 | loader: 'babel-loader', 25 | exclude: /node_modules/ 26 | }, 27 | { 28 | test: /\.css$/, 29 | loader: 'style-loader!css-loader' 30 | }, 31 | { 32 | test: /\.(eot|svg|ttf|woff|woff2)(\?\S*)?$/, 33 | loader: 'file-loader' 34 | }, 35 | { 36 | test: /\.(png|jpe?g|gif|svg)(\?\S*)?$/, 37 | loader: 'file-loader', 38 | query: { 39 | name: '[name].[ext]?[hash]' 40 | } 41 | } 42 | ] 43 | }, 44 | devServer: { 45 | historyApiFallback: true, 46 | noInfo: true 47 | }, 48 | devtool: '#eval-source-map' 49 | } 50 | 51 | if (process.env.NODE_ENV === 'production') { 52 | module.exports.devtool = '#source-map' 53 | // http://vue-loader.vuejs.org/en/workflow/production.html 54 | module.exports.plugins = (module.exports.plugins || []).concat([ 55 | new webpack.DefinePlugin({ 56 | 'process.env': { 57 | NODE_ENV: '"production"' 58 | } 59 | }), 60 | new webpack.optimize.UglifyJsPlugin({ 61 | compress: { 62 | warnings: false 63 | } 64 | }) 65 | ]) 66 | } 67 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/src/routes.js: -------------------------------------------------------------------------------- 1 | import Login from './components/login/login.vue' 2 | import Container from './components/container/container.vue' 3 | import UserHome from './components/container/userHome.vue' 4 | import Platform from './components/asideContainer/platform.vue' 5 | import UserList from './components/platform/userList.vue' 6 | import RightsManagement from './components/platform/rightsManagement.vue' 7 | import Goods from './components/asideContainer/goods.vue' 8 | import GoodsList from './components/goods/list.vue' 9 | import GoodsManagement from './components/goods/management.vue' 10 | 11 | import NotFound from './components/error/notFound.vue' 12 | 13 | export default [ 14 | { 15 | path: '/', 16 | component: Login 17 | }, 18 | { 19 | path: '/page', 20 | component: Container, 21 | children: [ 22 | { 23 | path: 'userHome', 24 | component: UserHome 25 | }, 26 | { 27 | path: 'platform', 28 | redirect: 'platform/userList', // 默认指向用户列表(UserList) 29 | component: Platform, 30 | children: [ 31 | { 32 | path: 'userList', 33 | component: UserList 34 | }, 35 | { 36 | path: 'rightsManagement', 37 | component: RightsManagement 38 | } 39 | ] 40 | }, 41 | { 42 | path: 'goods', 43 | component: Goods, 44 | children: [ 45 | { 46 | path: '/', 47 | component: GoodsList 48 | }, 49 | { 50 | path: 'management/:id?', // 匹配 /management 和 /management/x 两种情况 51 | component: GoodsManagement 52 | } 53 | ] 54 | } 55 | ] 56 | }, 57 | { // 404页面:必须位于最后,否则其它的路由地址都会使用 NotFound 组件 58 | path: '*', 59 | component: NotFound 60 | } 61 | ] 62 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/src/components/platform/rightsManagement.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 93 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/server/controllers/user.js: -------------------------------------------------------------------------------- 1 | const userModel = require('../models/user.js'); 2 | const jwt = require('koa-jwt'); 3 | const bcrypt = require('bcryptjs'); 4 | 5 | const postUserAuth = async function() { 6 | const data = this.request.body; // 用 post 传过来的数据存放于 request.body 7 | const userInfo = await userModel.getUserByName(data.name); 8 | 9 | if (userInfo != null) { // 如果查无此用户会返回 null 10 | if (userInfo.password != data.password) { 11 | if (!bcrypt.compareSync(data.password, userInfo.password)) { 12 | this.body = { // 返回给前端的数据 13 | success: false, 14 | info: '密码错误!' 15 | } 16 | } 17 | } else { // 密码正确 18 | const userToken = { 19 | id: userInfo.id, 20 | name: userInfo.user_name, 21 | originExp: Date.now() + 60 * 60 * 1000, // 设置过期时间(毫秒)为 1 小时 22 | } 23 | const secret = 'vue-koa-demo'; // 指定密钥,这是之后用来判断 token 合法性的标志 24 | const token = jwt.sign(userToken, secret); // 签发 token 25 | this.body = { 26 | success: true, 27 | token: token 28 | } 29 | } 30 | } else { 31 | this.body = { 32 | success: false, 33 | info: '用户不存在!' 34 | } 35 | } 36 | } 37 | 38 | const getUserInfo = async function() { 39 | const id = this.params.id; // 获取 url 里传过来的参数里的 id 40 | const result = await userModel.getUserById(id); 41 | 42 | if (result) { 43 | this.body = { 44 | success: true, 45 | list: [result], 46 | msg: '获取用户成功!' 47 | } 48 | } else { 49 | this.body = { 50 | success: false, 51 | list: [], 52 | msg: '用户不存在!' 53 | } 54 | } 55 | } 56 | 57 | const getUserList = async function() { 58 | const result = await userModel.getUserList(); 59 | 60 | this.body = { 61 | success: true, 62 | total: result.count, 63 | list: result.rows, 64 | msg: '获取用户列表成功!' 65 | } 66 | } 67 | 68 | module.exports = { 69 | postUserAuth, 70 | getUserInfo, 71 | getUserList 72 | } 73 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/server/controllers/goods.js: -------------------------------------------------------------------------------- 1 | const goodsModel = require('../models/goods.js'); 2 | 3 | const getGoodsList = async function() { 4 | const data = this.request.body; // post 请求,参数在 request.body 里 5 | const currentPage = Number(data.currentPage); 6 | const pageSize = Number(data.pageSize); 7 | const searchVal = data.searchVal; 8 | const result = await goodsModel.getGoodsList(searchVal); 9 | 10 | let list = result.rows; 11 | 12 | // 根据分页输出数据 13 | let start = pageSize * (currentPage - 1); 14 | list = list.slice(start, start + pageSize); 15 | 16 | this.body = { 17 | success: true, 18 | list, 19 | total: result.count, 20 | msg: '获取商品列表成功!' 21 | } 22 | } 23 | 24 | const getGoodsDetails = async function() { 25 | const id = this.params.id; 26 | const list = await goodsModel.getGoodsDetails(id); 27 | 28 | this.body = { 29 | success: true, 30 | list: Array.isArray(list) ? list : [list], 31 | msg: '获取商品详情成功!' 32 | }; 33 | } 34 | 35 | const manageGoods = async function() { 36 | const data = this.request.body; 37 | const id = data.id; 38 | const name = data.name; 39 | const description = data.description; 40 | const imgUrl = data.imgUrl; 41 | 42 | let success = false; 43 | let msg = ''; 44 | 45 | if (id) { 46 | if (name) { 47 | await goodsModel.updateGoods(id, name, description, imgUrl); 48 | success = true; 49 | msg = '修改成功!'; 50 | } 51 | } else if (name) { 52 | await goodsModel.addGoods(name, description, imgUrl); 53 | success = true; 54 | msg = '添加成功!'; 55 | } 56 | 57 | this.body = { 58 | success, 59 | msg 60 | } 61 | } 62 | 63 | const removeGoods = async function() { 64 | const id = this.params.id; 65 | 66 | await goodsModel.removeGoods(id); 67 | 68 | this.body = { 69 | success: true, 70 | msg: '删除成功!' 71 | } 72 | } 73 | 74 | module.exports = { 75 | getGoodsList, 76 | getGoodsDetails, 77 | removeGoods, 78 | manageGoods 79 | } 80 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/sql/my_test_db.sql: -------------------------------------------------------------------------------- 1 | -- -------------------------------------------------------- 2 | -- 主机: 127.0.0.1 3 | -- 服务器版本: 5.7.14 - MySQL Community Server (GPL) 4 | -- 服务器操作系统: Win64 5 | -- HeidiSQL 版本: 9.4.0.5125 6 | -- -------------------------------------------------------- 7 | 8 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 9 | /*!40101 SET NAMES utf8 */; 10 | /*!50503 SET NAMES utf8mb4 */; 11 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; 12 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; 13 | 14 | 15 | -- 导出 my_test_db 的数据库结构 16 | DROP DATABASE IF EXISTS `my_test_db`; 17 | CREATE DATABASE IF NOT EXISTS `my_test_db` /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci */; 18 | USE `my_test_db`; 19 | 20 | -- 导出 表 my_test_db.goods 结构 21 | DROP TABLE IF EXISTS `goods`; 22 | CREATE TABLE IF NOT EXISTS `goods` ( 23 | `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '商品id', 24 | `name` char(50) COLLATE utf8_unicode_ci NOT NULL COMMENT '商品名称', 25 | `description` char(200) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '商品描述', 26 | `img_url` varchar(500) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '商品图片路径', 27 | PRIMARY KEY (`id`) 28 | ) ENGINE=MyISAM AUTO_INCREMENT=13 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='商品'; 29 | 30 | -- 数据导出被取消选择。 31 | -- 导出 表 my_test_db.user 结构 32 | DROP TABLE IF EXISTS `user`; 33 | CREATE TABLE IF NOT EXISTS `user` ( 34 | `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户id', 35 | `user_name` char(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL COMMENT '用户名', 36 | `password` char(128) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL COMMENT '用户密码', 37 | PRIMARY KEY (`id`) 38 | ) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1 COMMENT='用户表'; 39 | 40 | -- 数据导出被取消选择。 41 | /*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */; 42 | /*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */; 43 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 44 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/src/components/login/login.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 67 | 68 | 79 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue2.x-koa2.x", 3 | "version": "0.0.1", 4 | "description": "A Vue and Koa project", 5 | "author": "", 6 | "private": true, 7 | "scripts": { 8 | "server": "node server/start.js", 9 | "dev": "node build/dev-server.js", 10 | "build": "node build/build.js" 11 | }, 12 | "dependencies": { 13 | "axios": "^0.15.3", 14 | "bcryptjs": "^2.4.0", 15 | "busboy": "^0.2.14", 16 | "element-ui": "^1.2.7", 17 | "koa": "^2.2.0", 18 | "koa-bodyparser": "^4.2.0", 19 | "koa-history-api-fallback": "^0.1.3", 20 | "koa-jwt": "^1.3.1", 21 | "koa-logger": "^2.0.1", 22 | "koa-router": "^5.4.0", 23 | "koa-static": "^3.0.0", 24 | "mysql": "^2.12.0", 25 | "sequelize": "^3.30.4", 26 | "stylus": "^0.54.5", 27 | "stylus-loader": "^2.4.0", 28 | "vue": "^2.2.6", 29 | "vue-router": "^2.3.0", 30 | "vuex": "^2.2.1" 31 | }, 32 | "devDependencies": { 33 | "autoprefixer": "^6.4.0", 34 | "babel-core": "^6.24.0", 35 | "babel-loader": "^6.4.1", 36 | "babel-plugin-transform-runtime": "^6.23.0", 37 | "babel-preset-es2015": "^6.24.0", 38 | "babel-preset-stage-0": "^6.22.0", 39 | "babel-register": "^6.24.0", 40 | "chalk": "^1.1.3", 41 | "connect-history-api-fallback": "^1.1.0", 42 | "css-loader": "^0.25.0", 43 | "eventsource-polyfill": "^0.9.6", 44 | "express": "^4.13.3", 45 | "extract-text-webpack-plugin": "^1.0.1", 46 | "file-loader": "^0.9.0", 47 | "friendly-errors-webpack-plugin": "^1.1.2", 48 | "function-bind": "^1.0.2", 49 | "html-webpack-plugin": "^2.8.1", 50 | "http-proxy-middleware": "^0.17.2", 51 | "json-loader": "^0.5.4", 52 | "opn": "^4.0.2", 53 | "ora": "^0.3.0", 54 | "semver": "^5.3.0", 55 | "shelljs": "^0.7.4", 56 | "url-loader": "^0.5.7", 57 | "vue-loader": "^10.0.0", 58 | "vue-style-loader": "^1.0.0", 59 | "vue-template-compiler": "^2.1.0", 60 | "webpack": "^1.9.11", 61 | "webpack-dev-middleware": "^1.8.3", 62 | "webpack-hot-middleware": "^2.12.2", 63 | "webpack-merge": "^0.14.1" 64 | }, 65 | "engines": { 66 | "node": ">= 4.0.0", 67 | "npm": ">= 3.0.0" 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/src/components/container/header.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 43 | 44 | 57 | 58 | 90 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/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 | // generate loader string to be used with extract text plugin 15 | function generateLoaders (loaders) { 16 | var sourceLoader = loaders.map(function (loader) { 17 | var extraParamChar 18 | if (/\?/.test(loader)) { 19 | loader = loader.replace(/\?/, '-loader?') 20 | extraParamChar = '&' 21 | } else { 22 | loader = loader + '-loader' 23 | extraParamChar = '?' 24 | } 25 | return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '') 26 | }).join('!') 27 | 28 | // Extract CSS when that option is specified 29 | // (which is the case during production build) 30 | if (options.extract) { 31 | return ExtractTextPlugin.extract('vue-style-loader', sourceLoader) 32 | } else { 33 | return ['vue-style-loader', sourceLoader].join('!') 34 | } 35 | } 36 | 37 | // http://vuejs.github.io/vue-loader/en/configurations/extract-css.html 38 | return { 39 | css: generateLoaders(['css']), 40 | postcss: generateLoaders(['css']), 41 | less: generateLoaders(['css', 'less']), 42 | sass: generateLoaders(['css', 'sass?indentedSyntax']), 43 | scss: generateLoaders(['css', 'sass']), 44 | stylus: generateLoaders(['css', 'stylus']), 45 | styl: generateLoaders(['css', 'stylus']) 46 | } 47 | } 48 | 49 | // Generate loaders for standalone style files (outside of .vue) 50 | exports.styleLoaders = function (options) { 51 | var output = [] 52 | var loaders = exports.cssLoaders(options) 53 | for (var extension in loaders) { 54 | var loader = loaders[extension] 55 | output.push({ 56 | test: new RegExp('\\.' + extension + '$'), 57 | loader: loader 58 | }) 59 | } 60 | return output 61 | } 62 | -------------------------------------------------------------------------------- /tree-menu/src/components/common/treeMenu.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 58 | 59 | 90 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/build/dev-server.js: -------------------------------------------------------------------------------- 1 | require('./check-versions')() 2 | var config = require('../config') 3 | if (!process.env.NODE_ENV) process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV) 4 | var path = require('path') 5 | var express = require('express') 6 | var webpack = require('webpack') 7 | var opn = require('opn') 8 | var proxyMiddleware = require('http-proxy-middleware') 9 | var webpackConfig = require('./webpack.dev.conf') 10 | 11 | // default port where dev server listens for incoming traffic 12 | var port = process.env.PORT || config.dev.port 13 | // Define HTTP proxies to your custom API backend 14 | // https://github.com/chimurai/http-proxy-middleware 15 | var proxyTable = config.dev.proxyTable 16 | 17 | var app = express() 18 | var compiler = webpack(webpackConfig) 19 | 20 | var devMiddleware = require('webpack-dev-middleware')(compiler, { 21 | publicPath: webpackConfig.output.publicPath, 22 | quiet: true 23 | }) 24 | 25 | var hotMiddleware = require('webpack-hot-middleware')(compiler, { 26 | log: () => {} 27 | }) 28 | // force page reload when html-webpack-plugin template changes 29 | compiler.plugin('compilation', function (compilation) { 30 | compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { 31 | hotMiddleware.publish({ action: 'reload' }) 32 | cb() 33 | }) 34 | }) 35 | 36 | // proxy api requests 37 | Object.keys(proxyTable).forEach(function (context) { 38 | var options = proxyTable[context] 39 | if (typeof options === 'string') { 40 | options = { target: options } 41 | } 42 | app.use(proxyMiddleware(context, options)) 43 | }) 44 | 45 | // handle fallback for HTML5 history API 46 | app.use(require('connect-history-api-fallback')()) 47 | 48 | // serve webpack bundle output 49 | app.use(devMiddleware) 50 | 51 | // enable hot-reload and state-preserving 52 | // compilation error display 53 | app.use(hotMiddleware) 54 | 55 | // serve pure static assets 56 | var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) 57 | app.use(staticPath, express.static('./static')) 58 | 59 | var uri = 'http://localhost:' + port 60 | 61 | devMiddleware.waitUntilValid(function () { 62 | console.log('> Listening at ' + uri + '\n') 63 | }) 64 | 65 | module.exports = app.listen(port, function (err) { 66 | if (err) { 67 | console.log(err) 68 | return 69 | } 70 | 71 | // when env is testing, don't need open it 72 | if (process.env.NODE_ENV !== 'testing') { 73 | opn(uri) 74 | } 75 | }) 76 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var utils = require('./utils') 4 | var projectRoot = path.resolve(__dirname, '../') 5 | 6 | var env = process.env.NODE_ENV 7 | // check env & config/index.js to decide whether to enable CSS source maps for the 8 | // various preprocessor loaders added to vue-loader at the end of this file 9 | var cssSourceMapDev = (env === 'development' && config.dev.cssSourceMap) 10 | var cssSourceMapProd = (env === 'production' && config.build.productionSourceMap) 11 | var useCssSourceMap = cssSourceMapDev || cssSourceMapProd 12 | 13 | module.exports = { 14 | entry: { 15 | app: './src/main.js' 16 | }, 17 | output: { 18 | path: config.build.assetsRoot, 19 | publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath, 20 | filename: '[name].js' 21 | }, 22 | resolve: { 23 | extensions: ['', '.js', '.vue', '.json'], 24 | fallback: [path.join(__dirname, '../node_modules')], 25 | alias: { 26 | 'vue$': 'vue/dist/vue.common.js', 27 | 'src': path.resolve(__dirname, '../src'), 28 | 'assets': path.resolve(__dirname, '../src/assets'), 29 | 'components': path.resolve(__dirname, '../src/components') 30 | } 31 | }, 32 | resolveLoader: { 33 | fallback: [path.join(__dirname, '../node_modules')] 34 | }, 35 | module: { 36 | loaders: [ 37 | { 38 | test: /\.vue$/, 39 | loader: 'vue' 40 | }, 41 | { 42 | test: /\.js$/, 43 | loader: 'babel', 44 | include: [ 45 | path.join(projectRoot, 'src') 46 | ], 47 | exclude: /node_modules/ 48 | }, 49 | { 50 | test: /\.json$/, 51 | loader: 'json' 52 | }, 53 | { 54 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 55 | loader: 'url', 56 | query: { 57 | limit: 10000, 58 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 59 | } 60 | }, 61 | { 62 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 63 | loader: 'url', 64 | query: { 65 | limit: 10000, 66 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 67 | } 68 | } 69 | ] 70 | }, 71 | vue: { 72 | loaders: utils.cssLoaders({ sourceMap: useCssSourceMap }), 73 | postcss: [ 74 | require('autoprefixer')({ 75 | browsers: ['last 2 versions'] 76 | }) 77 | ] 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/server/controllers/common/file.js: -------------------------------------------------------------------------------- 1 | const inspect = require('util').inspect 2 | const path = require('path') 3 | const fs = require('fs') 4 | const Busboy = require('busboy') 5 | 6 | /** 7 | * 同步创建文件目录 8 | * @param {string} dirname 目录绝对地址 9 | * @return {boolean} 创建目录结果 10 | */ 11 | function mkdirsSync( dirname ) { 12 | if (fs.existsSync( dirname )) { 13 | return true 14 | } else { 15 | if (mkdirsSync( path.dirname(dirname)) ) { 16 | fs.mkdirSync( dirname ) 17 | return true 18 | } 19 | } 20 | } 21 | 22 | /** 23 | * 获取上传文件的后缀名 24 | * @param {string} fileName 获取上传文件的后缀名 25 | * @return {string} 文件后缀名 26 | */ 27 | function getSuffixName( fileName ) { 28 | let nameList = fileName.split('.') 29 | return nameList[nameList.length - 1] 30 | } 31 | 32 | /** 33 | * 上传文件 34 | * @param {object} ctx koa上下文 35 | * @param {object} options 文件上传参数 36 | * dir 文件目录 37 | * path 文件存放路径 38 | * @return {promise} 39 | */ 40 | function uploadFile( ctx, options) { 41 | let req = ctx.req 42 | // let res = ctx.res 43 | let busboy = new Busboy({headers: req.headers}) 44 | 45 | // 获取类型 46 | let dir = options.dir || 'common' 47 | let filePath = path.join( options.path, dir) 48 | let mkdirResult = mkdirsSync( filePath ) 49 | 50 | return new Promise((resolve, reject) => { 51 | console.log('文件上传中...') 52 | let result = { 53 | success: false, 54 | filePath: '', 55 | formData: {}, 56 | } 57 | 58 | // 解析请求文件事件 59 | busboy.on('file', function(fieldname, file, filename, encoding, mimetype) { 60 | let fileName = Math.random().toString(16).substr(2) + '.' + getSuffixName(filename) 61 | let _uploadFilePath = path.join( filePath, fileName ) 62 | let saveTo = path.join(_uploadFilePath) 63 | 64 | // 文件保存到指定路径 65 | file.pipe(fs.createWriteStream(saveTo)) 66 | 67 | // 文件写入事件结束 68 | file.on('end', function() { 69 | result.success = true 70 | result.filePath = saveTo 71 | result.message = '文件上传成功' 72 | console.log('文件上传成功!') 73 | }) 74 | }) 75 | 76 | // 解析表单中其他字段信息 77 | busboy.on('field', function(fieldname, val, fieldnameTruncated, valTruncated, encoding, mimetype) { 78 | console.log('表单字段数据 [' + fieldname + ']: value: ' + inspect(val)); 79 | result.formData[fieldname] = inspect(val); 80 | }); 81 | 82 | // 解析结束事件 83 | busboy.on('finish', function() { 84 | console.log('文件上传结束') 85 | resolve(result) 86 | }) 87 | 88 | // 解析错误事件 89 | busboy.on('error', function(err) { 90 | console.log('文件上传出错') 91 | reject(result) 92 | }) 93 | 94 | req.pipe(busboy) 95 | }) 96 | } 97 | 98 | module.exports = { 99 | uploadFile 100 | } 101 | -------------------------------------------------------------------------------- /tree-menu/src/components/main.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 142 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var utils = require('./utils') 4 | var webpack = require('webpack') 5 | var merge = require('webpack-merge') 6 | var baseWebpackConfig = require('./webpack.base.conf') 7 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 8 | var HtmlWebpackPlugin = require('html-webpack-plugin') 9 | var env = config.build.env 10 | 11 | var webpackConfig = merge(baseWebpackConfig, { 12 | module: { 13 | loaders: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true }) 14 | }, 15 | devtool: config.build.productionSourceMap ? '#source-map' : false, 16 | output: { 17 | path: config.build.assetsRoot, 18 | filename: utils.assetsPath('js/[name].[chunkhash].js'), 19 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 20 | }, 21 | vue: { 22 | loaders: utils.cssLoaders({ 23 | sourceMap: config.build.productionSourceMap, 24 | extract: true 25 | }) 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 | }), 37 | new webpack.optimize.OccurrenceOrderPlugin(), 38 | // extract css into its own file 39 | new ExtractTextPlugin(utils.assetsPath('css/[name].[contenthash].css')), 40 | // generate dist index.html with correct asset hash for caching. 41 | // you can customize output by editing /index.html 42 | // see https://github.com/ampedandwired/html-webpack-plugin 43 | new HtmlWebpackPlugin({ 44 | filename: config.build.index, 45 | template: 'index.html', 46 | inject: true, 47 | minify: { 48 | removeComments: true, 49 | collapseWhitespace: true, 50 | removeAttributeQuotes: true 51 | // more options: 52 | // https://github.com/kangax/html-minifier#options-quick-reference 53 | }, 54 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 55 | chunksSortMode: 'dependency' 56 | }), 57 | // split vendor js into its own file 58 | new webpack.optimize.CommonsChunkPlugin({ 59 | name: 'vendor', 60 | minChunks: function (module, count) { 61 | // any required modules inside node_modules are extracted to vendor 62 | return ( 63 | module.resource && 64 | /\.js$/.test(module.resource) && 65 | module.resource.indexOf( 66 | path.join(__dirname, '../node_modules') 67 | ) === 0 68 | ) 69 | } 70 | }), 71 | // extract webpack runtime and module manifest to its own file in order to 72 | // prevent vendor hash from being updated whenever app bundle is updated 73 | new webpack.optimize.CommonsChunkPlugin({ 74 | name: 'manifest', 75 | chunks: ['vendor'] 76 | }) 77 | ] 78 | }) 79 | 80 | if (config.build.productionGzip) { 81 | var CompressionWebpackPlugin = require('compression-webpack-plugin') 82 | 83 | webpackConfig.plugins.push( 84 | new CompressionWebpackPlugin({ 85 | asset: '[path].gz[query]', 86 | algorithm: 'gzip', 87 | test: new RegExp( 88 | '\\.(' + 89 | config.build.productionGzipExtensions.join('|') + 90 | ')$' 91 | ), 92 | threshold: 10240, 93 | minRatio: 0.8 94 | }) 95 | ) 96 | } 97 | 98 | module.exports = webpackConfig 99 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/src/components/goods/list.vue: -------------------------------------------------------------------------------- 1 | 65 | 66 | 163 | -------------------------------------------------------------------------------- /vue2.x-koa2.x/src/components/goods/management.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 176 | --------------------------------------------------------------------------------