├── 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 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/vue2.x-koa2.x/src/components/error/notFound.vue:
--------------------------------------------------------------------------------
1 |
2 | 404,没有找到页面
3 |
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 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 |
12 |
13 |
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 |
2 |
3 |
4 |
主页:登录后的默认内容
5 |

6 |
7 |
8 |
9 |
10 |
22 |
--------------------------------------------------------------------------------
/vue2.x-koa2.x/src/components/container/container.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
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 |
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
14 |
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 |
2 |
3 |
4 |
5 |
6 |
7 | {{ model.menuName }}
8 |
9 |
12 |
13 |
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 |
2 |
8 |
12 |
13 |
17 |
18 |
22 |
23 |
24 |
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 |
2 |
7 |
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 |
2 |
3 |
4 |
5 | 欢迎登录
6 |
7 |
8 |
12 |
13 |
18 |
19 | 登录
20 |
21 |
22 |
23 |
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 |
2 |
15 |
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 |
2 |
11 |
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 |
2 |
3 |
4 |
5 |
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 |
2 |
3 |
19 |
20 |
26 |
29 |
30 |
33 |
34 |
37 |
38 |
41 |
42 |
43 |
44 |
45 |
47 |
48 | 编辑
49 | 删除
50 |
51 |
52 |
53 |
54 |
62 |
63 |
64 |
65 |
66 |
163 |
--------------------------------------------------------------------------------
/vue2.x-koa2.x/src/components/goods/management.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | 提交
25 | 重置
26 |
27 |
28 |
29 |
30 |
176 |
--------------------------------------------------------------------------------