├── admin
├── static
│ └── .gitkeep
├── build
│ ├── logo.png
│ ├── vue-loader.conf.js
│ ├── build.js
│ ├── check-versions.js
│ ├── webpack.base.conf.js
│ ├── webpack.dev.conf.js
│ ├── utils.js
│ └── webpack.prod.conf.js
├── config
│ ├── prod.env.js
│ ├── dev.env.js
│ └── index.js
├── src
│ ├── assets
│ │ ├── logo.png
│ │ ├── img
│ │ │ └── bg.jpg
│ │ └── css
│ │ │ └── base.css
│ ├── vuex
│ │ ├── types.js
│ │ ├── states.js
│ │ ├── index.js
│ │ ├── actions.js
│ │ └── mutations.js
│ ├── components
│ │ ├── Me.vue
│ │ ├── Error.vue
│ │ ├── HelloWorld.vue
│ │ ├── Aslider.vue
│ │ ├── Home.vue
│ │ ├── Login.vue
│ │ ├── Article.vue
│ │ ├── EditArticle.vue
│ │ ├── Types.vue
│ │ └── List.vue
│ ├── App.vue
│ ├── main.js
│ ├── api
│ │ └── index.js
│ ├── axios
│ │ └── index.js
│ └── router
│ │ └── index.js
├── .babelrc
├── .gitignore
├── .editorconfig
├── .postcssrc.js
├── README.md
├── package.json
└── index.html
├── front2
├── static
│ ├── .gitkeep
│ └── img
│ │ └── content
│ │ ├── banner.jpg
│ │ ├── circle.png
│ │ ├── news1.jpg
│ │ ├── news10.jpg
│ │ ├── news11.jpg
│ │ ├── news12.jpg
│ │ ├── news13.jpg
│ │ ├── news2.jpg
│ │ ├── news3.jpg
│ │ ├── news4.jpg
│ │ ├── news5.jpg
│ │ ├── news6.jpg
│ │ ├── news7.jpg
│ │ ├── news8.jpg
│ │ ├── news9.jpg
│ │ ├── slide1.jpg
│ │ ├── slide2.jpg
│ │ ├── spec1.jpg
│ │ ├── spec2.jpg
│ │ ├── spec3.jpg
│ │ ├── spec4.jpg
│ │ ├── article.jpg
│ │ ├── article2.jpg
│ │ ├── comment.png
│ │ └── twitter_fon.jpg
├── src
│ ├── assets
│ │ ├── css
│ │ │ ├── test.css
│ │ │ ├── fontello.css
│ │ │ ├── reset.css
│ │ │ └── typography.css
│ │ ├── logo.png
│ │ ├── fonts
│ │ │ ├── fontello.eot
│ │ │ ├── fontello.ttf
│ │ │ └── fontello.woff
│ │ ├── img
│ │ │ ├── content
│ │ │ │ ├── article.jpg
│ │ │ │ ├── banner.jpg
│ │ │ │ ├── circle.png
│ │ │ │ ├── comment.png
│ │ │ │ ├── news1.jpg
│ │ │ │ ├── news10.jpg
│ │ │ │ ├── news11.jpg
│ │ │ │ ├── news12.jpg
│ │ │ │ ├── news13.jpg
│ │ │ │ ├── news2.jpg
│ │ │ │ ├── news3.jpg
│ │ │ │ ├── news4.jpg
│ │ │ │ ├── news5.jpg
│ │ │ │ ├── news6.jpg
│ │ │ │ ├── news7.jpg
│ │ │ │ ├── news8.jpg
│ │ │ │ ├── news9.jpg
│ │ │ │ ├── slide1.jpg
│ │ │ │ ├── slide2.jpg
│ │ │ │ ├── spec1.jpg
│ │ │ │ ├── spec2.jpg
│ │ │ │ ├── spec3.jpg
│ │ │ │ ├── spec4.jpg
│ │ │ │ ├── article2.jpg
│ │ │ │ └── twitter_fon.jpg
│ │ │ └── png-sprite
│ │ │ │ └── 96dpi
│ │ │ │ └── sprite.png
│ │ └── js
│ │ │ └── main.js
│ ├── vuex
│ │ ├── states.js
│ │ ├── types.js
│ │ ├── index.js
│ │ ├── actions.js
│ │ └── mutations.js
│ ├── main.js
│ ├── router
│ │ └── index.js
│ ├── api
│ │ └── index.js
│ ├── components
│ │ ├── HelloWorld.vue
│ │ ├── Error.vue
│ │ ├── Footer.vue
│ │ ├── Search.vue
│ │ ├── Header.vue
│ │ ├── Detail.vue
│ │ └── List.vue
│ └── App.vue
├── build
│ ├── logo.png
│ ├── vue-loader.conf.js
│ ├── build.js
│ ├── check-versions.js
│ ├── webpack.base.conf.js
│ ├── webpack.dev.conf.js
│ ├── utils.js
│ └── webpack.prod.conf.js
├── config
│ ├── prod.env.js
│ ├── dev.env.js
│ └── index.js
├── .babelrc
├── .gitignore
├── .editorconfig
├── .postcssrc.js
├── README.md
├── index.html
└── package.json
├── codeimg
├── admin.png
├── front.png
└── article.png
├── server
├── uploads
│ ├── 1511862077020.jpg
│ ├── 1511862597885.png
│ ├── 1511862720206.jpg
│ ├── 1511925169452.jpg
│ ├── 1511925200028.jpg
│ ├── 1511946039405.png
│ └── 1512005562051.png
├── .gitignore
├── middlewares
│ └── response.js
├── config
│ └── index.js
├── token
│ ├── createToken.js
│ └── checkToken.js
├── package.json
├── app.js
├── controllers
│ ├── user.js
│ ├── type.js
│ ├── front.js
│ └── article.js
├── bin
│ └── www
├── routes
│ └── index.js
└── lib
│ └── mysql.js
└── README.md
/admin/static/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/front2/static/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/front2/src/assets/css/test.css:
--------------------------------------------------------------------------------
1 | body{
2 | background:red;
3 | }
--------------------------------------------------------------------------------
/codeimg/admin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/codeimg/admin.png
--------------------------------------------------------------------------------
/codeimg/front.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/codeimg/front.png
--------------------------------------------------------------------------------
/admin/build/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/admin/build/logo.png
--------------------------------------------------------------------------------
/codeimg/article.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/codeimg/article.png
--------------------------------------------------------------------------------
/front2/build/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/build/logo.png
--------------------------------------------------------------------------------
/admin/config/prod.env.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | module.exports = {
3 | NODE_ENV: '"production"'
4 | }
5 |
--------------------------------------------------------------------------------
/admin/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/admin/src/assets/logo.png
--------------------------------------------------------------------------------
/front2/config/prod.env.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | module.exports = {
3 | NODE_ENV: '"production"'
4 | }
5 |
--------------------------------------------------------------------------------
/front2/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/logo.png
--------------------------------------------------------------------------------
/admin/src/assets/img/bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/admin/src/assets/img/bg.jpg
--------------------------------------------------------------------------------
/front2/src/vuex/states.js:
--------------------------------------------------------------------------------
1 | const state = {
2 | type:'',
3 | activeType:''
4 | };
5 | export default state;
--------------------------------------------------------------------------------
/server/uploads/1511862077020.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/server/uploads/1511862077020.jpg
--------------------------------------------------------------------------------
/server/uploads/1511862597885.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/server/uploads/1511862597885.png
--------------------------------------------------------------------------------
/server/uploads/1511862720206.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/server/uploads/1511862720206.jpg
--------------------------------------------------------------------------------
/server/uploads/1511925169452.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/server/uploads/1511925169452.jpg
--------------------------------------------------------------------------------
/server/uploads/1511925200028.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/server/uploads/1511925200028.jpg
--------------------------------------------------------------------------------
/server/uploads/1511946039405.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/server/uploads/1511946039405.png
--------------------------------------------------------------------------------
/server/uploads/1512005562051.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/server/uploads/1512005562051.png
--------------------------------------------------------------------------------
/front2/src/assets/fonts/fontello.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/fonts/fontello.eot
--------------------------------------------------------------------------------
/front2/src/assets/fonts/fontello.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/fonts/fontello.ttf
--------------------------------------------------------------------------------
/front2/static/img/content/banner.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/static/img/content/banner.jpg
--------------------------------------------------------------------------------
/front2/static/img/content/circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/static/img/content/circle.png
--------------------------------------------------------------------------------
/front2/static/img/content/news1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/static/img/content/news1.jpg
--------------------------------------------------------------------------------
/front2/static/img/content/news10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/static/img/content/news10.jpg
--------------------------------------------------------------------------------
/front2/static/img/content/news11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/static/img/content/news11.jpg
--------------------------------------------------------------------------------
/front2/static/img/content/news12.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/static/img/content/news12.jpg
--------------------------------------------------------------------------------
/front2/static/img/content/news13.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/static/img/content/news13.jpg
--------------------------------------------------------------------------------
/front2/static/img/content/news2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/static/img/content/news2.jpg
--------------------------------------------------------------------------------
/front2/static/img/content/news3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/static/img/content/news3.jpg
--------------------------------------------------------------------------------
/front2/static/img/content/news4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/static/img/content/news4.jpg
--------------------------------------------------------------------------------
/front2/static/img/content/news5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/static/img/content/news5.jpg
--------------------------------------------------------------------------------
/front2/static/img/content/news6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/static/img/content/news6.jpg
--------------------------------------------------------------------------------
/front2/static/img/content/news7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/static/img/content/news7.jpg
--------------------------------------------------------------------------------
/front2/static/img/content/news8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/static/img/content/news8.jpg
--------------------------------------------------------------------------------
/front2/static/img/content/news9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/static/img/content/news9.jpg
--------------------------------------------------------------------------------
/front2/static/img/content/slide1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/static/img/content/slide1.jpg
--------------------------------------------------------------------------------
/front2/static/img/content/slide2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/static/img/content/slide2.jpg
--------------------------------------------------------------------------------
/front2/static/img/content/spec1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/static/img/content/spec1.jpg
--------------------------------------------------------------------------------
/front2/static/img/content/spec2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/static/img/content/spec2.jpg
--------------------------------------------------------------------------------
/front2/static/img/content/spec3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/static/img/content/spec3.jpg
--------------------------------------------------------------------------------
/front2/static/img/content/spec4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/static/img/content/spec4.jpg
--------------------------------------------------------------------------------
/admin/src/vuex/types.js:
--------------------------------------------------------------------------------
1 | export const LOGIN = 'LOGIN';
2 | export const LOGOUT = 'LOGOUT';
3 | export const USERNAME = 'USERNAME'
--------------------------------------------------------------------------------
/front2/src/assets/fonts/fontello.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/fonts/fontello.woff
--------------------------------------------------------------------------------
/front2/static/img/content/article.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/static/img/content/article.jpg
--------------------------------------------------------------------------------
/front2/static/img/content/article2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/static/img/content/article2.jpg
--------------------------------------------------------------------------------
/front2/static/img/content/comment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/static/img/content/comment.png
--------------------------------------------------------------------------------
/front2/src/assets/img/content/article.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/content/article.jpg
--------------------------------------------------------------------------------
/front2/src/assets/img/content/banner.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/content/banner.jpg
--------------------------------------------------------------------------------
/front2/src/assets/img/content/circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/content/circle.png
--------------------------------------------------------------------------------
/front2/src/assets/img/content/comment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/content/comment.png
--------------------------------------------------------------------------------
/front2/src/assets/img/content/news1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/content/news1.jpg
--------------------------------------------------------------------------------
/front2/src/assets/img/content/news10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/content/news10.jpg
--------------------------------------------------------------------------------
/front2/src/assets/img/content/news11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/content/news11.jpg
--------------------------------------------------------------------------------
/front2/src/assets/img/content/news12.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/content/news12.jpg
--------------------------------------------------------------------------------
/front2/src/assets/img/content/news13.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/content/news13.jpg
--------------------------------------------------------------------------------
/front2/src/assets/img/content/news2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/content/news2.jpg
--------------------------------------------------------------------------------
/front2/src/assets/img/content/news3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/content/news3.jpg
--------------------------------------------------------------------------------
/front2/src/assets/img/content/news4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/content/news4.jpg
--------------------------------------------------------------------------------
/front2/src/assets/img/content/news5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/content/news5.jpg
--------------------------------------------------------------------------------
/front2/src/assets/img/content/news6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/content/news6.jpg
--------------------------------------------------------------------------------
/front2/src/assets/img/content/news7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/content/news7.jpg
--------------------------------------------------------------------------------
/front2/src/assets/img/content/news8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/content/news8.jpg
--------------------------------------------------------------------------------
/front2/src/assets/img/content/news9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/content/news9.jpg
--------------------------------------------------------------------------------
/front2/src/assets/img/content/slide1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/content/slide1.jpg
--------------------------------------------------------------------------------
/front2/src/assets/img/content/slide2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/content/slide2.jpg
--------------------------------------------------------------------------------
/front2/src/assets/img/content/spec1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/content/spec1.jpg
--------------------------------------------------------------------------------
/front2/src/assets/img/content/spec2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/content/spec2.jpg
--------------------------------------------------------------------------------
/front2/src/assets/img/content/spec3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/content/spec3.jpg
--------------------------------------------------------------------------------
/front2/src/assets/img/content/spec4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/content/spec4.jpg
--------------------------------------------------------------------------------
/front2/static/img/content/twitter_fon.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/static/img/content/twitter_fon.jpg
--------------------------------------------------------------------------------
/front2/src/assets/img/content/article2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/content/article2.jpg
--------------------------------------------------------------------------------
/front2/src/assets/img/content/twitter_fon.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/content/twitter_fon.jpg
--------------------------------------------------------------------------------
/front2/src/assets/img/png-sprite/96dpi/sprite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yxliam/vue-node/HEAD/front2/src/assets/img/png-sprite/96dpi/sprite.png
--------------------------------------------------------------------------------
/front2/src/vuex/types.js:
--------------------------------------------------------------------------------
1 | export const HANDLE_TYPE = 'HANDLE_TYPE';
2 | export const HANDLE_ACTIVE = 'HANDLE_ACTIVE'
3 | export const SEARCH_TEXT = 'SEARCH_TEXT'
--------------------------------------------------------------------------------
/admin/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["env", {
4 | "modules": false
5 | }],
6 | "stage-2"
7 | ],
8 | "plugins": ["transform-runtime"]
9 | }
10 |
--------------------------------------------------------------------------------
/admin/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | dist/
4 |
5 | # Editor directories and files
6 | .idea
7 | .vscode
8 | *.suo
9 | *.ntvs*
10 | *.njsproj
11 | *.sln
12 |
--------------------------------------------------------------------------------
/front2/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["env", {
4 | "modules": false
5 | }],
6 | "stage-2"
7 | ],
8 | "plugins": ["transform-runtime"]
9 | }
10 |
--------------------------------------------------------------------------------
/front2/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | dist/
4 |
5 | # Editor directories and files
6 | .idea
7 | .vscode
8 | *.suo
9 | *.ntvs*
10 | *.njsproj
11 | *.sln
12 |
--------------------------------------------------------------------------------
/admin/src/vuex/states.js:
--------------------------------------------------------------------------------
1 | const state = {
2 | token: window.sessionStorage.getItem('token'),
3 | username:window.sessionStorage.getItem('username')
4 | };
5 | export default state;
--------------------------------------------------------------------------------
/server/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | dist/
4 |
5 |
6 | # Editor directories and files
7 | .idea
8 | .vscode
9 | *.suo
10 | *.ntvs*
11 | *.njsproj
12 | *.sln
13 |
--------------------------------------------------------------------------------
/admin/src/components/Me.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | 关于我
4 |
5 |
6 |
11 |
14 |
--------------------------------------------------------------------------------
/admin/config/dev.env.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const merge = require('webpack-merge')
3 | const prodEnv = require('./prod.env')
4 |
5 | module.exports = merge(prodEnv, {
6 | NODE_ENV: '"development"'
7 | })
8 |
--------------------------------------------------------------------------------
/front2/config/dev.env.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const merge = require('webpack-merge')
3 | const prodEnv = require('./prod.env')
4 |
5 | module.exports = merge(prodEnv, {
6 | NODE_ENV: '"development"'
7 | })
8 |
--------------------------------------------------------------------------------
/admin/.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 |
--------------------------------------------------------------------------------
/admin/src/components/Error.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | 404
4 |
5 |
6 |
7 |
12 |
15 |
--------------------------------------------------------------------------------
/front2/.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 |
--------------------------------------------------------------------------------
/server/middlewares/response.js:
--------------------------------------------------------------------------------
1 | module.exports = async (ctx,next)=>{
2 | //请求成功
3 | //code 1:err 2:success
4 | ctx.jsonReturn = ({code,data,msg}) =>{
5 | ctx.body = { code , data, msg };
6 | };
7 | //传递给下一个中间件
8 | await next();
9 |
10 | }
--------------------------------------------------------------------------------
/admin/.postcssrc.js:
--------------------------------------------------------------------------------
1 | // https://github.com/michael-ciniawsky/postcss-load-config
2 |
3 | module.exports = {
4 | "plugins": {
5 | // to edit target browsers: use "browserslist" field in package.json
6 | "postcss-import": {},
7 | "autoprefixer": {}
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/front2/.postcssrc.js:
--------------------------------------------------------------------------------
1 | // https://github.com/michael-ciniawsky/postcss-load-config
2 |
3 | module.exports = {
4 | "plugins": {
5 | // to edit target browsers: use "browserslist" field in package.json
6 | "postcss-import": {},
7 | "autoprefixer": {}
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/admin/src/vuex/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 | import state from './states.js'
4 | import mutations from './mutations.js'
5 | import actions from './actions.js'
6 | Vue.use( Vuex )
7 | export default new Vuex.Store({
8 | state,
9 | mutations,
10 | actions
11 | })
12 |
--------------------------------------------------------------------------------
/front2/src/vuex/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 | import state from './states.js'
4 | import mutations from './mutations.js'
5 | import actions from './actions.js'
6 | Vue.use( Vuex )
7 | export default new Vuex.Store({
8 | state,
9 | mutations,
10 | actions
11 | })
12 |
--------------------------------------------------------------------------------
/admin/src/vuex/actions.js:
--------------------------------------------------------------------------------
1 | import * as types from './types.js'
2 |
3 | export default{
4 | UserLogin({commit},data){
5 | commit(types.LOGIN,data);
6 | },
7 | UserLogout({commit}){
8 | commit(types.LOGOUT)
9 | },
10 | UserName({commit},data){
11 | commit(types.USERNAME,data)
12 | }
13 |
14 | }
--------------------------------------------------------------------------------
/front2/src/vuex/actions.js:
--------------------------------------------------------------------------------
1 | import * as types from './types.js'
2 |
3 | export default{
4 | handleType({commit},data){
5 | commit(types.HANDLE_TYPE,data);
6 | },
7 | handleList({commit},data){
8 | commit(types.HANDLE_ACTIVE,data);
9 | },
10 | handleSearch({commit},data){
11 | commit(types.SEARCH_TEXT,data)
12 | }
13 |
14 |
15 | }
--------------------------------------------------------------------------------
/server/config/index.js:
--------------------------------------------------------------------------------
1 | const config = {
2 | dev:{
3 | //启动端口
4 | port:3000,
5 | //数据库配置
6 | database:{
7 | DATABASE: 'vue_new',
8 | USERNAME: 'root',
9 | PASSWORD: 'root',
10 | PORT: '3306',
11 | HOST: 'localhost'
12 | }
13 | },
14 |
15 | }
16 |
17 | module.exports = config
--------------------------------------------------------------------------------
/server/token/createToken.js:
--------------------------------------------------------------------------------
1 | const jwt = require('jsonwebtoken');
2 |
3 | //登录时:核对用户名和密码成功后,应用将用户的id(图中的user_id)作为JWT Payload的一个属性
4 | module.exports = function(user_id){
5 | const token = jwt.sign({
6 | user_id: user_id
7 | }, 'yxl', {
8 | expiresIn: '3600s' //过期时间设置为60妙。那么decode这个token的时候得到的过期时间为 : 创建token的时间 + 设置的值
9 | });
10 | return token;
11 | };
--------------------------------------------------------------------------------
/front2/src/vuex/mutations.js:
--------------------------------------------------------------------------------
1 | import * as types from './types.js'
2 |
3 | const mutations = {
4 | [types.HANDLE_TYPE]:(state,data)=>{
5 | state.type = data
6 | },
7 | [types.HANDLE_ACTIVE]:(state,data)=>{
8 | state.activeType = data
9 | },
10 | [types.SEARCH_TEXT]:(state,data)=>{
11 | state.search = data
12 | }
13 | }
14 |
15 | export default mutations
--------------------------------------------------------------------------------
/admin/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
26 |
27 |
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## vue+node 博客系统
2 | ### 技术栈 vue2+vuex+axios+vue-router+koa2+mysql
3 | ### front2 是前台展示 admin 是管理后台 server是nodejs服务接口
4 | ### 前台展示
5 | 
6 | 
7 | ### 后台展示
8 | 
9 |
10 | ```
11 | 页面太多就没有全部展示了,因为自己的虚拟机空间不足,所以没有部署上去
12 | ```
13 | [工具站传送门](https://www.toolbon.com/)
14 |
--------------------------------------------------------------------------------
/front2/src/main.js:
--------------------------------------------------------------------------------
1 | // The Vue build version to load with the `import` command
2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
3 | import Vue from 'vue'
4 | import App from './App'
5 | import router from './router'
6 | import store from './vuex'
7 |
8 | import './assets/css/main.css'
9 |
10 |
11 | Vue.config.productionTip = false
12 |
13 | /* eslint-disable no-new */
14 | new Vue({
15 | el: '#app',
16 | router,
17 | store,
18 | template: '',
19 | components: { App }
20 | })
21 |
--------------------------------------------------------------------------------
/admin/README.md:
--------------------------------------------------------------------------------
1 | # admin
2 |
3 | > A Vue.js project
4 |
5 | ## Build Setup
6 |
7 | ``` bash
8 | # install dependencies
9 | npm install
10 |
11 | # serve with hot reload at localhost:8080
12 | npm run dev
13 |
14 | # build for production with minification
15 | npm run build
16 |
17 | # build for production and view the bundle analyzer report
18 | npm run build --report
19 | ```
20 |
21 | For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader).
22 |
--------------------------------------------------------------------------------
/front2/README.md:
--------------------------------------------------------------------------------
1 | # front2
2 |
3 | > A Vue.js project
4 |
5 | ## Build Setup
6 |
7 | ``` bash
8 | # install dependencies
9 | npm install
10 |
11 | # serve with hot reload at localhost:8080
12 | npm run dev
13 |
14 | # build for production with minification
15 | npm run build
16 |
17 | # build for production and view the bundle analyzer report
18 | npm run build --report
19 | ```
20 |
21 | For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader).
22 |
--------------------------------------------------------------------------------
/admin/src/vuex/mutations.js:
--------------------------------------------------------------------------------
1 | import * as types from './types.js'
2 |
3 | const mutations = {
4 | [types.LOGIN]:(state,data)=>{
5 | window.sessionStorage.setItem('token',data)
6 | state.token = data
7 | },
8 | [types.LOGOUT]:(state,data)=>{
9 | window.sessionStorage.removeItem('token')
10 | window.sessionStorage.removeItem('username')
11 | state.token = null;
12 | },
13 | [types.USERNAME]:(state,data)=>{
14 | window.sessionStorage.setItem('username',data)
15 | state.username = data
16 | }
17 | }
18 |
19 | export default mutations
--------------------------------------------------------------------------------
/admin/src/main.js:
--------------------------------------------------------------------------------
1 | // The Vue build version to load with the `import` command
2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
3 | import Vue from 'vue'
4 | import App from './App'
5 | import router from './router'
6 | import ElementUI from 'element-ui'
7 | import 'element-ui/lib/theme-chalk/index.css'
8 | import "./assets/css/base.css"
9 |
10 |
11 | import store from './vuex'
12 |
13 | Vue.use(ElementUI)
14 |
15 |
16 | Vue.config.productionTip = false
17 |
18 | /* eslint-disable no-new */
19 | new Vue({
20 | el: '#app',
21 | router,
22 | store,
23 | template: '',
24 | components: { App }
25 | })
26 |
--------------------------------------------------------------------------------
/admin/build/vue-loader.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const utils = require('./utils')
3 | const config = require('../config')
4 | const isProduction = process.env.NODE_ENV === 'production'
5 | const sourceMapEnabled = isProduction
6 | ? config.build.productionSourceMap
7 | : config.dev.cssSourceMap
8 |
9 |
10 | module.exports = {
11 | loaders: utils.cssLoaders({
12 | sourceMap: sourceMapEnabled,
13 | extract: isProduction
14 | }),
15 | cssSourceMap: sourceMapEnabled,
16 | cacheBusting: config.dev.cacheBusting,
17 | transformToRequire: {
18 | video: 'src',
19 | source: 'src',
20 | img: 'src',
21 | image: 'xlink:href'
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/front2/build/vue-loader.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const utils = require('./utils')
3 | const config = require('../config')
4 | const isProduction = process.env.NODE_ENV === 'production'
5 | const sourceMapEnabled = isProduction
6 | ? config.build.productionSourceMap
7 | : config.dev.cssSourceMap
8 |
9 |
10 | module.exports = {
11 | loaders: utils.cssLoaders({
12 | sourceMap: sourceMapEnabled,
13 | extract: isProduction
14 | }),
15 | cssSourceMap: sourceMapEnabled,
16 | cacheBusting: config.dev.cacheBusting,
17 | transformToRequire: {
18 | video: 'src',
19 | source: 'src',
20 | img: 'src',
21 | image: 'xlink:href'
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "start": "node bin/www",
7 | "dev": "./node_modules/.bin/nodemon bin/www",
8 | "prd": "pm2 start bin/www",
9 | "test": "echo \"Error: no test specified\" && exit 1"
10 | },
11 | "dependencies": {
12 | "debug": "^2.6.3",
13 | "jsonwebtoken": "^8.1.0",
14 | "koa": "^2.2.0",
15 | "koa-bodyparser": "^3.2.0",
16 | "koa-convert": "^1.2.0",
17 | "koa-json": "^2.0.2",
18 | "koa-logger": "^2.0.1",
19 | "koa-multer": "^1.0.2",
20 | "koa-onerror": "^1.2.1",
21 | "koa-router": "^7.1.1",
22 | "koa-static": "^3.0.0",
23 | "koa-views": "^5.2.1",
24 | "moment": "^2.19.2",
25 | "mysql": "^2.15.0",
26 | "pug": "^2.0.0-rc.1"
27 | },
28 | "devDependencies": {
29 | "nodemon": "^1.8.1"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/server/token/checkToken.js:
--------------------------------------------------------------------------------
1 | const jwt = require('jsonwebtoken');
2 | //检查token是否过期
3 | module.exports = async ( ctx, next ) => {
4 | if(ctx.request.header['authorization']){
5 | let token = ctx.request.header['authorization'].split(' ')[1];
6 | //解码token
7 | let decoded = jwt.decode(token, 'yxl');
8 | //console.log(decoded);的输出 :{ user_id: '123123123', iat: 1494405235, exp: 1494405235 }
9 | if(token && decoded.exp <= new Date()/1000){
10 | ctx.status = 401;
11 | ctx.body = {
12 | code:1,
13 | msg:'token过期',
14 | data:[]
15 | };
16 | }else{
17 | //如果权限没问题,那么交个下一个控制器处理
18 | return next();
19 | }
20 | }else{
21 | ctx.status = 401;
22 | ctx.body = {
23 | code:1,
24 | msg:'token err',
25 | data:[]
26 | }
27 | }
28 | };
29 |
30 |
--------------------------------------------------------------------------------
/server/app.js:
--------------------------------------------------------------------------------
1 | const Koa = require('koa')
2 | const app = new Koa()
3 | const views = require('koa-views')
4 | const json = require('koa-json')
5 | const onerror = require('koa-onerror')
6 | const bodyparser = require('koa-bodyparser')
7 | const logger = require('koa-logger')
8 | const static = require("koa-static");
9 | //返回数据中间件
10 | const response = require('./middlewares/response.js')
11 |
12 | const index = require('./routes/index')
13 |
14 | // error handler
15 | app.use(response)
16 |
17 | onerror(app)
18 | app.use(static(__dirname + '/uploads'));
19 |
20 | // middlewares
21 | app.use(bodyparser({
22 | enableTypes:['json', 'form', 'text']
23 | }))
24 | app.use(json())
25 | app.use(logger())
26 |
27 |
28 |
29 | // logger
30 | app.use(async (ctx, next) => {
31 | const start = new Date()
32 | await next()
33 | const ms = new Date() - start
34 | console.log(`${ctx.method} ${ctx.url} - ${ms}ms`)
35 | })
36 |
37 | // routes
38 | app.use(index.routes(), index.allowedMethods())
39 |
40 | // error-handling
41 | app.on('error', (err, ctx) => {
42 | console.error('server error', err, ctx)
43 | });
44 |
45 | module.exports = app
46 |
--------------------------------------------------------------------------------
/admin/build/build.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | require('./check-versions')()
3 |
4 | process.env.NODE_ENV = 'production'
5 |
6 | const ora = require('ora')
7 | const rm = require('rimraf')
8 | const path = require('path')
9 | const chalk = require('chalk')
10 | const webpack = require('webpack')
11 | const config = require('../config')
12 | const webpackConfig = require('./webpack.prod.conf')
13 |
14 | const spinner = ora('building for production...')
15 | spinner.start()
16 |
17 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
18 | if (err) throw err
19 | webpack(webpackConfig, function (err, stats) {
20 | spinner.stop()
21 | if (err) throw err
22 | process.stdout.write(stats.toString({
23 | colors: true,
24 | modules: false,
25 | children: false,
26 | chunks: false,
27 | chunkModules: false
28 | }) + '\n\n')
29 |
30 | if (stats.hasErrors()) {
31 | console.log(chalk.red(' Build failed with errors.\n'))
32 | process.exit(1)
33 | }
34 |
35 | console.log(chalk.cyan(' Build complete.\n'))
36 | console.log(chalk.yellow(
37 | ' Tip: built files are meant to be served over an HTTP server.\n' +
38 | ' Opening index.html over file:// won\'t work.\n'
39 | ))
40 | })
41 | })
42 |
--------------------------------------------------------------------------------
/front2/build/build.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | require('./check-versions')()
3 |
4 | process.env.NODE_ENV = 'production'
5 |
6 | const ora = require('ora')
7 | const rm = require('rimraf')
8 | const path = require('path')
9 | const chalk = require('chalk')
10 | const webpack = require('webpack')
11 | const config = require('../config')
12 | const webpackConfig = require('./webpack.prod.conf')
13 |
14 | const spinner = ora('building for production...')
15 | spinner.start()
16 |
17 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
18 | if (err) throw err
19 | webpack(webpackConfig, function (err, stats) {
20 | spinner.stop()
21 | if (err) throw err
22 | process.stdout.write(stats.toString({
23 | colors: true,
24 | modules: false,
25 | children: false,
26 | chunks: false,
27 | chunkModules: false
28 | }) + '\n\n')
29 |
30 | if (stats.hasErrors()) {
31 | console.log(chalk.red(' Build failed with errors.\n'))
32 | process.exit(1)
33 | }
34 |
35 | console.log(chalk.cyan(' Build complete.\n'))
36 | console.log(chalk.yellow(
37 | ' Tip: built files are meant to be served over an HTTP server.\n' +
38 | ' Opening index.html over file:// won\'t work.\n'
39 | ))
40 | })
41 | })
42 |
--------------------------------------------------------------------------------
/front2/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 | import HelloWorld from '@/components/HelloWorld'
4 |
5 | Vue.use(Router)
6 |
7 | const Home = resolve => require(['@/components/Home.vue'], resolve);
8 | const Error = resolve => require(['@/components/Error.vue'], resolve);
9 | const Post = resolve => require(['@/components/Detail.vue'], resolve);
10 | const List = resolve => require(['@/components/List.vue'], resolve);
11 | const Search = resolve => require(['@/components/Search.vue'], resolve);
12 |
13 |
14 | export default new Router({
15 | mode: 'history',
16 | scrollBehavior(to, from, savedPosition){
17 | if(savedPosition){
18 | return savedPosition;
19 | }
20 | if(to.meta.scrollTop === true){
21 | return { x: 0, y: 0 };
22 | }
23 | },
24 | routes: [
25 | {
26 | path: '/',
27 | name: 'Home',
28 | component: Home
29 | },
30 | {
31 | path:'/post/:aid',
32 | name:'Post',
33 | component:Post,
34 | meta: { scrollTop: true }
35 | },{
36 | path:'/list_front/:tid',
37 | name:'List',
38 | component:List
39 | },
40 | {
41 | path:'/search/:text',
42 | name:'Search',
43 | component:Search
44 | },
45 | {
46 | path:'*',
47 | name:'Error',
48 | component:Error
49 | }
50 | ]
51 | })
52 |
--------------------------------------------------------------------------------
/front2/src/api/index.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 |
3 | export default{
4 | //获取类型
5 | frontGetAllType(data){
6 | return axios.post('/api/type_all_front',data)
7 | },
8 | //根据tid 获取列表
9 | getTidList(data){
10 | return axios.post('/api/type_article_list_front',data)
11 | },
12 | //根据id 获取前4阅读量
13 | getTop4List(data){
14 | return axios.post('/api/get_for_article_front',data)
15 | },
16 | //获取推荐文章
17 | getRecommendArticle(data){
18 | return axios.post('/api/get_recommend_front',data)
19 | },
20 | //获取文章
21 | getArticle(data){
22 | return axios.post('/api/get_article_front',data)
23 | },
24 | //修改文章阅读
25 | updateCons(data){
26 | return axios.post('/api/update_article_consult_front',data)
27 | },
28 | //获取轮播
29 | getSliderList(){
30 | return axios.post('/api/select_slider_front')
31 | },
32 | //首页列表图
33 | getHomeList(data){
34 | return axios.post('/api/home_list_front',data)
35 | },
36 | //首页最新文章
37 | getNewList(data){
38 | return axios.post('/api/home_new_front',data)
39 | },
40 | //首页类型列表
41 | getTypeList(data){
42 | return axios.post('/api/home_type_list_front',data)
43 | },
44 | //搜索
45 | searchList(data){
46 | return axios.post('/api/home_search_front',data)
47 | }
48 |
49 | }
--------------------------------------------------------------------------------
/admin/src/api/index.js:
--------------------------------------------------------------------------------
1 | import axios from '../axios'
2 |
3 | export default{
4 | // 登录
5 | localLogin(data){
6 | return axios.post('/api/login',data)
7 | },
8 | //添加栏目
9 | localAddType(data){
10 | return axios.post('/api/add_type',data)
11 | },
12 | //查询所有栏目
13 | localTypeAll(data){
14 | return axios.post('/api/type_all',data)
15 | },
16 | //删除栏目
17 | localTypeDel(data){
18 | return axios.post('/api/del_type',data)
19 | },
20 | //编辑栏目
21 | localTypeEdit(data){
22 | return axios.post('/api/edit_type',data)
23 | },
24 | //添加文章
25 | localAddArticle(data){
26 | return axios.post('/api/add_article',data)
27 | },
28 | //文章列表
29 | localArticleList(data){
30 | return axios.post('/api/get_article_list',data)
31 | },
32 | //文章查找
33 | localgetArticle(data){
34 | return axios.post('/api/get_article',data)
35 | },
36 | //编辑文章
37 | localEditArticle(data){
38 | return axios.post('/api/edit_article',data)
39 | },
40 | //修改文章状态
41 | localUpdateState(data){
42 | return axios.post('/api/update_state',data)
43 | },
44 | //删除文章
45 | localDelArticle(data){
46 | return axios.post('/api/del_article',data)
47 | },
48 | //缩略图上传
49 | localUpload(data){
50 | return axios.post('/api/upload',data)
51 | },
52 | //推荐文章
53 | localRecommend(data){
54 | return axios.post('/api/set_recommend',data)
55 | },
56 | //设置轮播
57 | localSetSlider(data){
58 | return axios.post('/api/set_slider',data)
59 | }
60 | }
--------------------------------------------------------------------------------
/admin/build/check-versions.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const chalk = require('chalk')
3 | const semver = require('semver')
4 | const packageConfig = require('../package.json')
5 | const shell = require('shelljs')
6 | function exec (cmd) {
7 | return require('child_process').execSync(cmd).toString().trim()
8 | }
9 |
10 | const versionRequirements = [
11 | {
12 | name: 'node',
13 | currentVersion: semver.clean(process.version),
14 | versionRequirement: packageConfig.engines.node
15 | }
16 | ]
17 |
18 | if (shell.which('npm')) {
19 | versionRequirements.push({
20 | name: 'npm',
21 | currentVersion: exec('npm --version'),
22 | versionRequirement: packageConfig.engines.npm
23 | })
24 | }
25 |
26 | module.exports = function () {
27 | const warnings = []
28 | for (let i = 0; i < versionRequirements.length; i++) {
29 | const mod = versionRequirements[i]
30 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
31 | warnings.push(mod.name + ': ' +
32 | chalk.red(mod.currentVersion) + ' should be ' +
33 | chalk.green(mod.versionRequirement)
34 | )
35 | }
36 | }
37 |
38 | if (warnings.length) {
39 | console.log('')
40 | console.log(chalk.yellow('To use this template, you must update following to modules:'))
41 | console.log()
42 | for (let i = 0; i < warnings.length; i++) {
43 | const warning = warnings[i]
44 | console.log(' ' + warning)
45 | }
46 | console.log()
47 | process.exit(1)
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/front2/build/check-versions.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const chalk = require('chalk')
3 | const semver = require('semver')
4 | const packageConfig = require('../package.json')
5 | const shell = require('shelljs')
6 | function exec (cmd) {
7 | return require('child_process').execSync(cmd).toString().trim()
8 | }
9 |
10 | const versionRequirements = [
11 | {
12 | name: 'node',
13 | currentVersion: semver.clean(process.version),
14 | versionRequirement: packageConfig.engines.node
15 | }
16 | ]
17 |
18 | if (shell.which('npm')) {
19 | versionRequirements.push({
20 | name: 'npm',
21 | currentVersion: exec('npm --version'),
22 | versionRequirement: packageConfig.engines.npm
23 | })
24 | }
25 |
26 | module.exports = function () {
27 | const warnings = []
28 | for (let i = 0; i < versionRequirements.length; i++) {
29 | const mod = versionRequirements[i]
30 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
31 | warnings.push(mod.name + ': ' +
32 | chalk.red(mod.currentVersion) + ' should be ' +
33 | chalk.green(mod.versionRequirement)
34 | )
35 | }
36 | }
37 |
38 | if (warnings.length) {
39 | console.log('')
40 | console.log(chalk.yellow('To use this template, you must update following to modules:'))
41 | console.log()
42 | for (let i = 0; i < warnings.length; i++) {
43 | const warning = warnings[i]
44 | console.log(' ' + warning)
45 | }
46 | console.log()
47 | process.exit(1)
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/admin/src/components/HelloWorld.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ msg }}
4 |
Essential Links
5 |
13 |
Ecosystem
14 |
20 |
21 |
22 |
23 |
33 |
34 |
35 |
51 |
--------------------------------------------------------------------------------
/front2/src/components/HelloWorld.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ msg }}
4 |
Essential Links
5 |
13 |
Ecosystem
14 |
20 |
21 |
22 |
23 |
33 |
34 |
35 |
51 |
--------------------------------------------------------------------------------
/admin/src/axios/index.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import store from '../vuex'
3 | import router from '../router'
4 |
5 | //设置全局axios默认值
6 | axios.defaults.timeout = 5000; //5000的超时验证
7 | axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';
8 |
9 | //创建一个axios实例
10 | const instance = axios.create();
11 | instance.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';
12 |
13 | axios.interceptors.request.use = instance.interceptors.request.use;
14 |
15 | //request拦截器
16 | instance.interceptors.request.use(
17 | config => {
18 | //每次发送请求之前检测都vuex存有token,那么都要放在请求头发送给服务器
19 | if(store.state.token){
20 | config.headers.Authorization = `token ${store.state.token}`;
21 | }
22 | return config;
23 | },
24 | err => {
25 | return Promise.reject(err);
26 | }
27 | );
28 | //respone拦截器
29 | instance.interceptors.response.use(
30 | response => {
31 | return response;
32 | },
33 | error => { //默认除了2XX之外的都是错误的,就会走这里
34 | if(error.response){
35 | switch(error.response.status){
36 | case 401:
37 | store.dispatch('UserLogout'); //可能是token过期,清除它
38 | router.replace({ //跳转到登录页面
39 | path: '/login',
40 | query: { redirect: router.currentRoute.fullPath } // 将跳转的路由path作为参数,登录成功后跳转到该路由
41 | });
42 | }
43 | }
44 | return Promise.reject(error.response);
45 | }
46 | );
47 |
48 | export default instance;
49 |
--------------------------------------------------------------------------------
/admin/src/assets/css/base.css:
--------------------------------------------------------------------------------
1 | /*css 初始化 */
2 | html, body, ul, li, ol, dl, dd, dt, p, h1, h2, h3, h4, h5, h6, form, fieldset, legend, img {
3 | margin: 0;
4 | padding: 0;
5 | }
6 | *{
7 | font-family:"Microsoft YaHei", "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
8 | }
9 |
10 | /*各浏览器显示不同,去掉蓝色边框*/
11 | fieldset, img, input, button {
12 | border: none;
13 | padding: 0;
14 | margin: 0;
15 | outline-style: none;
16 | }
17 |
18 | ul, ol {
19 | list-style: none;
20 | }
21 |
22 | input {
23 | padding-top: 0;
24 | padding-bottom: 0;
25 | font-family: "Microsoft yaHei";
26 | }
27 |
28 | /*去掉行内替换元素空白缝隙*/
29 | select, input {
30 | vertical-align: middle;
31 | }
32 |
33 | select, input, textarea {
34 | margin: 0;
35 | }
36 |
37 | /*防止拖动 影响布局*/
38 | textarea {
39 | resize: none;
40 | }
41 |
42 | /*去掉行内替换元素空白缝隙*/
43 | img {
44 | border: 0;
45 | vertical-align: middle;
46 | }
47 |
48 | table {
49 | border-collapse: collapse;
50 | }
51 |
52 | /*清除浮动*/
53 | .clearfix:before, .clearfix:after {
54 | content: "";
55 | display: table;
56 | }
57 |
58 | .clearfix:after {
59 | clear: both;
60 | }
61 |
62 | .clearfix {
63 | *zoom: 1; /*IE/7/6*/
64 | }
65 | li{
66 | list-style: none;
67 | }
68 | a{
69 | text-decoration: none;
70 | }
71 | h1, h2, h3, h4, h5, h6 {
72 | text-decoration: none;
73 | font-weight: normal;
74 | font-size: 100%;
75 | }
76 | /*浮动*/
77 | .fl{
78 | float: left;
79 | }
80 | .fr{
81 | float: right;
82 | }
83 | .ml25{
84 | margin-left: 25px;
85 | }
86 | .body {
87 | width: 100%;
88 | position: relative;
89 | }
--------------------------------------------------------------------------------
/front2/src/components/Error.vue:
--------------------------------------------------------------------------------
1 |
2 |
27 |
28 |
33 |
45 |
--------------------------------------------------------------------------------
/front2/src/components/Footer.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
34 |
35 |
40 |
43 |
--------------------------------------------------------------------------------
/server/controllers/user.js:
--------------------------------------------------------------------------------
1 | const Model = require('../lib/mysql.js');
2 | const createToken = require('../token/createToken.js');
3 | class UserController{
4 | //用户登录
5 | static async loginPost(ctx){
6 | //es6 解构
7 | //这里解构需要和 ctx.request.body 的对象属性相同
8 | const { username,password } = ctx.request.body;
9 | await Model.dologin(username,password)
10 | .then(result=>{
11 | var res = JSON.parse(JSON.stringify(result))
12 | if(res.length <= 0){
13 | ctx.jsonReturn({
14 | code:1,
15 | msg:'用户名或者密码错误'
16 | })
17 | }else{
18 | let token = createToken(username);
19 | var updateinfo = Model.updateUserToken([token,res[0]['id']])
20 | if(updateinfo){
21 | ctx.jsonReturn({
22 | code:2,
23 | data:{
24 | token:token,
25 | username:username
26 | },
27 | msg:'登录成功'
28 | })
29 |
30 | }else{
31 | ctx.jsonReturn({
32 | code:1,
33 | msg:'登录失败'
34 | })
35 | }
36 | }
37 | }).catch(err=>{
38 | ctx.jsonReturn({
39 | code:1,
40 | msg:'服务器异常'
41 | })
42 | })
43 | }
44 |
45 | }
46 |
47 | module.exports = UserController;
--------------------------------------------------------------------------------
/admin/build/webpack.base.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const path = require('path')
3 | const utils = require('./utils')
4 | const config = require('../config')
5 | const vueLoaderConfig = require('./vue-loader.conf')
6 |
7 | function resolve (dir) {
8 | return path.join(__dirname, '..', dir)
9 | }
10 |
11 | module.exports = {
12 | context: path.resolve(__dirname, '../'),
13 | entry: {
14 | app: './src/main.js'
15 | },
16 | output: {
17 | path: config.build.assetsRoot,
18 | filename: '[name].js',
19 | publicPath: process.env.NODE_ENV === 'production'
20 | ? config.build.assetsPublicPath
21 | : config.dev.assetsPublicPath
22 | },
23 | resolve: {
24 | extensions: ['.js', '.vue', '.json'],
25 | alias: {
26 | 'vue$': 'vue/dist/vue.esm.js',
27 | '@': resolve('src'),
28 | }
29 | },
30 | module: {
31 | rules: [
32 | {
33 | test: /\.vue$/,
34 | loader: 'vue-loader',
35 | options: vueLoaderConfig
36 | },
37 | {
38 | test: /\.js$/,
39 | loader: 'babel-loader',
40 | include: [resolve('src'), resolve('test')]
41 | },
42 | {
43 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
44 | loader: 'url-loader',
45 | options: {
46 | limit: 10000,
47 | name: utils.assetsPath('img/[name].[hash:7].[ext]')
48 | }
49 | },
50 | {
51 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
52 | loader: 'url-loader',
53 | options: {
54 | limit: 10000,
55 | name: utils.assetsPath('media/[name].[hash:7].[ext]')
56 | }
57 | },
58 | {
59 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
60 | loader: 'url-loader',
61 | options: {
62 | limit: 10000,
63 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
64 | }
65 | }
66 | ]
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/front2/build/webpack.base.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const path = require('path')
3 | const utils = require('./utils')
4 | const config = require('../config')
5 | const vueLoaderConfig = require('./vue-loader.conf')
6 |
7 | function resolve (dir) {
8 | return path.join(__dirname, '..', dir)
9 | }
10 |
11 | module.exports = {
12 | context: path.resolve(__dirname, '../'),
13 | entry: {
14 | app: './src/main.js'
15 | },
16 | output: {
17 | path: config.build.assetsRoot,
18 | filename: '[name].js',
19 | publicPath: process.env.NODE_ENV === 'production'
20 | ? config.build.assetsPublicPath
21 | : config.dev.assetsPublicPath
22 | },
23 | resolve: {
24 | extensions: ['.js', '.vue', '.json'],
25 | alias: {
26 | 'vue$': 'vue/dist/vue.esm.js',
27 | '@': resolve('src'),
28 | }
29 | },
30 | module: {
31 | rules: [
32 | {
33 | test: /\.vue$/,
34 | loader: 'vue-loader',
35 | options: vueLoaderConfig
36 | },
37 | {
38 | test: /\.js$/,
39 | loader: 'babel-loader',
40 | include: [resolve('src'), resolve('test')]
41 | },
42 | {
43 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
44 | loader: 'url-loader',
45 | options: {
46 | limit: 10000,
47 | name: utils.assetsPath('img/[name].[hash:7].[ext]')
48 | }
49 | },
50 | {
51 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
52 | loader: 'url-loader',
53 | options: {
54 | limit: 10000,
55 | name: utils.assetsPath('media/[name].[hash:7].[ext]')
56 | }
57 | },
58 | {
59 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
60 | loader: 'url-loader',
61 | options: {
62 | limit: 10000,
63 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
64 | }
65 | },
66 |
67 | ]
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/front2/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
57 |
58 |
76 |
--------------------------------------------------------------------------------
/admin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "admin",
3 | "version": "1.0.0",
4 | "description": "A Vue.js project",
5 | "author": "yxl720 <676557432@qq.com>",
6 | "private": true,
7 | "scripts": {
8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
9 | "start": "npm run dev",
10 | "build": "node build/build.js"
11 | },
12 | "dependencies": {
13 | "mavon-editor": "^2.4.0",
14 | "vue": "^2.5.2",
15 | "vue-router": "^3.0.1"
16 | },
17 | "devDependencies": {
18 | "autoprefixer": "^7.1.2",
19 | "babel-core": "^6.22.1",
20 | "babel-loader": "^7.1.1",
21 | "babel-plugin-transform-runtime": "^6.22.0",
22 | "babel-preset-env": "^1.3.2",
23 | "babel-preset-stage-2": "^6.22.0",
24 | "babel-register": "^6.22.0",
25 | "chalk": "^2.0.1",
26 | "copy-webpack-plugin": "^4.0.1",
27 | "css-loader": "^0.28.0",
28 | "eventsource-polyfill": "^0.9.6",
29 | "extract-text-webpack-plugin": "^3.0.0",
30 | "file-loader": "^1.1.4",
31 | "friendly-errors-webpack-plugin": "^1.6.1",
32 | "html-webpack-plugin": "^2.30.1",
33 | "node-notifier": "^5.1.2",
34 | "node-sass": "^4.7.2",
35 | "optimize-css-assets-webpack-plugin": "^3.2.0",
36 | "ora": "^1.2.0",
37 | "portfinder": "^1.0.13",
38 | "postcss-import": "^11.0.0",
39 | "postcss-loader": "^2.0.8",
40 | "rimraf": "^2.6.0",
41 | "sass-loader": "^6.0.6",
42 | "semver": "^5.3.0",
43 | "shelljs": "^0.7.6",
44 | "url-loader": "^0.5.8",
45 | "vue-loader": "^13.3.0",
46 | "vue-style-loader": "^3.0.1",
47 | "vue-template-compiler": "^2.5.2",
48 | "webpack": "^3.6.0",
49 | "webpack-bundle-analyzer": "^2.9.0",
50 | "webpack-dev-server": "^2.9.1",
51 | "webpack-merge": "^4.1.0"
52 | },
53 | "engines": {
54 | "node": ">= 4.0.0",
55 | "npm": ">= 3.0.0"
56 | },
57 | "browserslist": [
58 | "> 1%",
59 | "last 2 versions",
60 | "not ie <= 8"
61 | ]
62 | }
63 |
--------------------------------------------------------------------------------
/admin/src/components/Aslider.vue:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
24 |
61 |
--------------------------------------------------------------------------------
/server/bin/www:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /**
4 | * Module dependencies.
5 | */
6 |
7 | var app = require('../app');
8 | var debug = require('debug')('demo:server');
9 | var http = require('http');
10 |
11 | /**
12 | * Get port from environment and store in Express.
13 | */
14 |
15 | var port = normalizePort(process.env.PORT || '3000');
16 | // app.set('port', port);
17 |
18 | /**
19 | * Create HTTP server.
20 | */
21 |
22 | var server = http.createServer(app.callback());
23 |
24 | /**
25 | * Listen on provided port, on all network interfaces.
26 | */
27 |
28 | server.listen(port);
29 | server.on('error', onError);
30 | server.on('listening', onListening);
31 |
32 | /**
33 | * Normalize a port into a number, string, or false.
34 | */
35 |
36 | function normalizePort(val) {
37 | var port = parseInt(val, 10);
38 |
39 | if (isNaN(port)) {
40 | // named pipe
41 | return val;
42 | }
43 |
44 | if (port >= 0) {
45 | // port number
46 | return port;
47 | }
48 |
49 | return false;
50 | }
51 |
52 | /**
53 | * Event listener for HTTP server "error" event.
54 | */
55 |
56 | function onError(error) {
57 | if (error.syscall !== 'listen') {
58 | throw error;
59 | }
60 |
61 | var bind = typeof port === 'string'
62 | ? 'Pipe ' + port
63 | : 'Port ' + port;
64 |
65 | // handle specific listen errors with friendly messages
66 | switch (error.code) {
67 | case 'EACCES':
68 | console.error(bind + ' requires elevated privileges');
69 | process.exit(1);
70 | break;
71 | case 'EADDRINUSE':
72 | console.error(bind + ' is already in use');
73 | process.exit(1);
74 | break;
75 | default:
76 | throw error;
77 | }
78 | }
79 |
80 | /**
81 | * Event listener for HTTP server "listening" event.
82 | */
83 |
84 | function onListening() {
85 | var addr = server.address();
86 | var bind = typeof addr === 'string'
87 | ? 'pipe ' + addr
88 | : 'port ' + addr.port;
89 | debug('Listening on ' + bind);
90 | }
91 |
--------------------------------------------------------------------------------
/admin/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | front2
7 |
53 |
54 |
55 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/front2/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | front2
7 |
53 |
54 |
55 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/front2/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "front2",
3 | "version": "1.0.0",
4 | "description": "A Vue.js project",
5 | "author": "yxl720 <676557432@qq.com>",
6 | "private": true,
7 | "scripts": {
8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
9 | "start": "npm run dev",
10 | "build": "node build/build.js"
11 | },
12 | "dependencies": {
13 | "axios": "^0.17.1",
14 | "marked": "^0.3.6",
15 | "mavon-editor": "^2.4.7",
16 | "node-loader": "^0.6.0",
17 | "node-sass": "^4.7.2",
18 | "sass-loader": "^6.0.6",
19 | "vue": "^2.5.2",
20 | "vue-loading-template": "^0.1.7",
21 | "vue-router": "^3.0.1",
22 | "vuex": "^3.0.1"
23 | },
24 | "devDependencies": {
25 | "autoprefixer": "^7.1.2",
26 | "babel-core": "^6.22.1",
27 | "babel-loader": "^7.1.1",
28 | "babel-plugin-transform-runtime": "^6.22.0",
29 | "babel-preset-env": "^1.3.2",
30 | "babel-preset-stage-2": "^6.22.0",
31 | "babel-register": "^6.22.0",
32 | "chalk": "^2.0.1",
33 | "copy-webpack-plugin": "^4.0.1",
34 | "css-loader": "^0.28.0",
35 | "eventsource-polyfill": "^0.9.6",
36 | "extract-text-webpack-plugin": "^3.0.0",
37 | "file-loader": "^1.1.4",
38 | "friendly-errors-webpack-plugin": "^1.6.1",
39 | "html-webpack-plugin": "^2.30.1",
40 | "webpack-bundle-analyzer": "^2.9.0",
41 | "node-notifier": "^5.1.2",
42 | "postcss-import": "^11.0.0",
43 | "postcss-loader": "^2.0.8",
44 | "semver": "^5.3.0",
45 | "shelljs": "^0.7.6",
46 | "optimize-css-assets-webpack-plugin": "^3.2.0",
47 | "ora": "^1.2.0",
48 | "rimraf": "^2.6.0",
49 | "url-loader": "^0.5.8",
50 | "vue-loader": "^13.3.0",
51 | "vue-style-loader": "^3.0.1",
52 | "vue-template-compiler": "^2.5.2",
53 | "portfinder": "^1.0.13",
54 | "webpack": "^3.6.0",
55 | "webpack-dev-server": "^2.9.1",
56 | "webpack-merge": "^4.1.0"
57 | },
58 | "engines": {
59 | "node": ">= 4.0.0",
60 | "npm": ">= 3.0.0"
61 | },
62 | "browserslist": [
63 | "> 1%",
64 | "last 2 versions",
65 | "not ie <= 8"
66 | ]
67 | }
68 |
--------------------------------------------------------------------------------
/front2/src/assets/css/fontello.css:
--------------------------------------------------------------------------------
1 | /* SVG - fonts */
2 | @font-face {
3 | font-family: 'fontello';
4 | src: url("../fonts/fontello.eot?44020949");
5 | src: url("../fonts/fontello.eot?44020949#iefix") format("embedded-opentype"), url("../fonts/fontello.woff?44020949") format("woff"), url("../fonts/fontello.ttf?44020949") format("truetype");
6 | font-weight: normal;
7 | font-style: normal;
8 | }
9 |
10 | [class^="icon-"]:before, [class*=" icon-"]:before {
11 | font-family: "fontello";
12 | font-style: normal;
13 | font-weight: normal;
14 | speak: none;
15 | display: inline-block;
16 | text-decoration: inherit;
17 | width: 1em;
18 | margin-right: .2em;
19 | text-align: center;
20 | /* opacity: .8; */
21 | /* For safety - reset parent styles, that can break glyph codes*/
22 | font-variant: normal;
23 | text-transform: none;
24 | /* fix buttons height, for twitter bootstrap */
25 | line-height: 1em;
26 | /* Animation center compensation - margins should be symmetric */
27 | /* remove if not needed */
28 | margin-left: .2em;
29 | /* you can be more comfortable with increased icons size */
30 | /* font-size: 120%; */
31 | /* Font smoothing. That was taken from TWBS */
32 | -webkit-font-smoothing: antialiased;
33 | -moz-osx-font-smoothing: grayscale;
34 | /* Uncomment for 3D effect */
35 | /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
36 | }
37 |
38 | .icon-sun:before {
39 | content: '\e800';
40 | }
41 |
42 | .icon-euro:before {
43 | content: '\e801';
44 | }
45 |
46 | .icon-search:before {
47 | content: '\e802';
48 | }
49 |
50 | .icon-down-open:before {
51 | content: '\e803';
52 | }
53 |
54 | .icon-up-open:before {
55 | content: '\e804';
56 | }
57 |
58 | .icon-play:before {
59 | content: '\e805';
60 | }
61 |
62 | .icon-facebook:before {
63 | content: '\e806';
64 | }
65 |
66 | .icon-gplus:before {
67 | content: '\e807';
68 | }
69 |
70 | .icon-twitter:before {
71 | content: '\e808';
72 | }
73 |
74 | .icon-eye:before {
75 | content: '\e809';
76 | }
77 |
78 | .icon-comment-empty:before {
79 | content: '\e80a';
80 | }
81 |
82 | .icon-reply:before {
83 | content: '\e80b';
84 | }
85 |
86 | .icon-arrows-cw:before {
87 | content: '\e80c';
88 | }
89 |
90 | /* end SVG - fonts */
--------------------------------------------------------------------------------
/admin/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 | import store from '../vuex'
4 |
5 | const Home = resolve => require(['@/components/Home.vue'], resolve);
6 | const Error = resolve => require(['@/components/Error.vue'], resolve);
7 | const Login = resolve => require(['@/components/Login.vue'], resolve);
8 | const Article = resolve => require(['@/components/Article.vue'], resolve);
9 | const List = resolve => require(['@/components/List.vue'], resolve);
10 | const Types = resolve => require(['@/components/Types.vue'], resolve);
11 | const Me = resolve => require(['@/components/Me.vue'], resolve);
12 | const EditArticle = resolve => require(['@/components/EditArticle.vue'], resolve);
13 | Vue.use(Router)
14 |
15 | const router = new Router({
16 | mode: 'history',
17 | routes: [
18 | {
19 | path: '/admin',
20 | name: 'Home',
21 | component: Home,
22 | redirect:'/admin/article',
23 | meta:{
24 | auth:true,
25 | title:'首页'
26 | },
27 | children:[
28 | {
29 | path:'article',
30 | component:Article,
31 | meta:{
32 | auth:true,
33 | title:'发布文章'
34 | }
35 | },
36 | {
37 | path:'editArticle/:id',
38 | component:EditArticle,
39 | meta:{
40 | auth:true,
41 | title:'编辑文章'
42 | }
43 | }
44 | ,{
45 | path:'list',
46 | component:List,
47 | meta:{
48 | auth:true,
49 | title:'文章管理'
50 | }
51 | },{
52 | path:'types',
53 | component:Types,
54 | meta:{
55 | auth:true,
56 | title:'栏目管理'
57 | }
58 | },{
59 | path:'about',
60 | component:Me,
61 | meta:{
62 | auth:true,
63 | title:'关于我'
64 | }
65 | }
66 | ]
67 | },
68 | {
69 | path:'/login',
70 | component:Login,
71 | meta:{
72 | title:'登录'
73 | }
74 | },
75 | {
76 | path:'*',
77 | name:'Error',
78 | component:Error,
79 | meta:{
80 | title:'Error'
81 | }
82 | }
83 | ]
84 | })
85 | //在全局导航钩子中检查 meta 字段
86 | router.beforeEach((to, from, next) => {
87 | let token = store.state.token;
88 | document.title = to.meta.title || document.title
89 | if(to.meta.auth){
90 | if(token){
91 | return next();
92 | }
93 | next({
94 | path: '/login',
95 | query: { redirect: to.fullPath }
96 | })
97 | }else{
98 | next();
99 | }
100 | });
101 |
102 | export default router;
103 |
--------------------------------------------------------------------------------
/admin/build/webpack.dev.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const utils = require('./utils')
3 | const webpack = require('webpack')
4 | const config = require('../config')
5 | const merge = require('webpack-merge')
6 | const baseWebpackConfig = require('./webpack.base.conf')
7 | const HtmlWebpackPlugin = require('html-webpack-plugin')
8 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
9 | const portfinder = require('portfinder')
10 |
11 | const devWebpackConfig = merge(baseWebpackConfig, {
12 | module: {
13 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
14 | },
15 | // cheap-module-eval-source-map is faster for development
16 | devtool: config.dev.devtool,
17 |
18 | // these devServer options should be customized in /config/index.js
19 | devServer: {
20 | clientLogLevel: 'warning',
21 | historyApiFallback: true,
22 | hot: true,
23 | compress: true,
24 | host: process.env.HOST || config.dev.host,
25 | port: process.env.PORT || config.dev.port,
26 | open: config.dev.autoOpenBrowser,
27 | overlay: config.dev.errorOverlay ? {
28 | warnings: false,
29 | errors: true,
30 | } : false,
31 | publicPath: config.dev.assetsPublicPath,
32 | proxy: config.dev.proxyTable,
33 | quiet: true, // necessary for FriendlyErrorsPlugin
34 | watchOptions: {
35 | poll: config.dev.poll,
36 | }
37 | },
38 | plugins: [
39 | new webpack.DefinePlugin({
40 | 'process.env': require('../config/dev.env')
41 | }),
42 | new webpack.HotModuleReplacementPlugin(),
43 | new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
44 | new webpack.NoEmitOnErrorsPlugin(),
45 | // https://github.com/ampedandwired/html-webpack-plugin
46 | new HtmlWebpackPlugin({
47 | filename: 'index.html',
48 | template: 'index.html',
49 | inject: true
50 | }),
51 | ]
52 | })
53 |
54 | module.exports = new Promise((resolve, reject) => {
55 | portfinder.basePort = process.env.PORT || config.dev.port
56 | portfinder.getPort((err, port) => {
57 | if (err) {
58 | reject(err)
59 | } else {
60 | // publish the new Port, necessary for e2e tests
61 | process.env.PORT = port
62 | // add port to devServer config
63 | devWebpackConfig.devServer.port = port
64 |
65 | // Add FriendlyErrorsPlugin
66 | devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
67 | compilationSuccessInfo: {
68 | messages: [`Your application is running here: http://${config.dev.host}:${port}`],
69 | },
70 | onErrors: config.dev.notifyOnErrors
71 | ? utils.createNotifierCallback()
72 | : undefined
73 | }))
74 |
75 | resolve(devWebpackConfig)
76 | }
77 | })
78 | })
79 |
--------------------------------------------------------------------------------
/front2/build/webpack.dev.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const utils = require('./utils')
3 | const webpack = require('webpack')
4 | const config = require('../config')
5 | const merge = require('webpack-merge')
6 | const baseWebpackConfig = require('./webpack.base.conf')
7 | const HtmlWebpackPlugin = require('html-webpack-plugin')
8 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
9 | const portfinder = require('portfinder')
10 |
11 | const devWebpackConfig = merge(baseWebpackConfig, {
12 | module: {
13 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
14 | },
15 | // cheap-module-eval-source-map is faster for development
16 | devtool: config.dev.devtool,
17 |
18 | // these devServer options should be customized in /config/index.js
19 | devServer: {
20 | clientLogLevel: 'warning',
21 | historyApiFallback: true,
22 | hot: true,
23 | compress: true,
24 | host: process.env.HOST || config.dev.host,
25 | port: process.env.PORT || config.dev.port,
26 | open: config.dev.autoOpenBrowser,
27 | overlay: config.dev.errorOverlay ? {
28 | warnings: false,
29 | errors: true,
30 | } : false,
31 | publicPath: config.dev.assetsPublicPath,
32 | proxy: config.dev.proxyTable,
33 | quiet: true, // necessary for FriendlyErrorsPlugin
34 | watchOptions: {
35 | poll: config.dev.poll,
36 | }
37 | },
38 | plugins: [
39 | new webpack.DefinePlugin({
40 | 'process.env': require('../config/dev.env')
41 | }),
42 | new webpack.HotModuleReplacementPlugin(),
43 | new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
44 | new webpack.NoEmitOnErrorsPlugin(),
45 | // https://github.com/ampedandwired/html-webpack-plugin
46 | new HtmlWebpackPlugin({
47 | filename: 'index.html',
48 | template: 'index.html',
49 | inject: true
50 | }),
51 | ]
52 | })
53 |
54 | module.exports = new Promise((resolve, reject) => {
55 | portfinder.basePort = process.env.PORT || config.dev.port
56 | portfinder.getPort((err, port) => {
57 | if (err) {
58 | reject(err)
59 | } else {
60 | // publish the new Port, necessary for e2e tests
61 | process.env.PORT = port
62 | // add port to devServer config
63 | devWebpackConfig.devServer.port = port
64 |
65 | // Add FriendlyErrorsPlugin
66 | devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
67 | compilationSuccessInfo: {
68 | messages: [`Your application is running here: http://${config.dev.host}:${port}`],
69 | },
70 | onErrors: config.dev.notifyOnErrors
71 | ? utils.createNotifierCallback()
72 | : undefined
73 | }))
74 |
75 | resolve(devWebpackConfig)
76 | }
77 | })
78 | })
79 |
--------------------------------------------------------------------------------
/server/routes/index.js:
--------------------------------------------------------------------------------
1 | const router = require('koa-router')()
2 | const multer = require('koa-multer');//加载koa-multer模块
3 | //checkToken作为中间件存在
4 | const checkToken = require('../token/checkToken.js');
5 | const User = require('../controllers/user.js');
6 | const Type = require('../controllers/type.js');
7 | const Article = require('../controllers/article.js');
8 | const Front = require('../controllers/front.js')
9 |
10 | //配置
11 | var storage = multer.diskStorage({
12 | //文件保存路径
13 | destination: function (req, file, cb) {
14 | cb(null, 'uploads/')
15 | },
16 | //修改文件名称
17 | filename: function (req, file, cb) {
18 | var fileFormat = (file.originalname).split(".");
19 | cb(null,Date.now() + "." + fileFormat[fileFormat.length - 1]);
20 | }
21 | })
22 | //加载配置
23 | var upload = multer({ storage: storage });
24 |
25 | //后台接口
26 | //登录
27 | router.post('/login',User.loginPost);
28 | //添加栏目
29 | router.post('/add_type',checkToken,Type.createType)
30 | //查询所有栏目
31 | router.post('/type_all',checkToken,Type.selectTypeAll)
32 | //删除栏目
33 | router.post('/del_type',checkToken,Type.delectTypeById);
34 | //修改栏目
35 | router.post('/edit_type',checkToken,Type.editTypeById);
36 | //添加文章
37 | router.post('/add_article',checkToken,Article.createArticle)
38 | //文章列表
39 | router.post('/get_article_list',checkToken,Article.getArticleList)
40 | //查找文章
41 | router.post('/get_article',checkToken,Article.getArticle)
42 | //编辑文章
43 | router.post('/edit_article',checkToken,Article.editArticle)
44 | //文章状态
45 | router.post('/update_state',checkToken,Article.updateState)
46 | //文章删除
47 | router.post('/del_article',checkToken,Article.delArticleById)
48 | //缩略图上传
49 | router.post('/upload', upload.single('file'), async (ctx, next) => {
50 | console.log( ctx );
51 | ctx.body = {
52 | filename: 'http://'+ctx.host+'/'+ctx.req.file.filename//返回文件名
53 | }
54 | })
55 | //推荐
56 | router.post('/set_recommend',checkToken,Article.setRecommend)
57 | //设置轮播
58 | router.post('/set_slider',checkToken,Article.setSliderCon)
59 |
60 |
61 | //前台接口
62 | router.post('/type_all_front',Type.selectTypeAll)
63 | //根据tid 查找相关文章
64 | router.post('/type_article_list_front',Front.articleList)
65 | //前4阅读
66 | router.post('/get_for_article_front',Front.getMostConstuList)
67 | //推荐文章
68 | router.post('/get_recommend_front',Front.getRecommend)
69 | //获取文章
70 | router.post('/get_article_front',Front.findArticleById)
71 | //修改阅读
72 | router.post('/update_article_consult_front',Front.updateConsult)
73 | //轮播查询
74 | router.post('/select_slider_front',Front.selectSlider)
75 | //首页文章列表
76 | router.post('/home_list_front',Front.homeList)
77 | //首页最新文章
78 | router.post('/home_new_front',Front.newList)
79 | //首页类型文章
80 | router.post('/home_type_list_front',Front.getTypeList)
81 | //搜索
82 | router.post('/home_search_front',Front.searchArticleList)
83 |
84 |
85 | module.exports = router
86 |
--------------------------------------------------------------------------------
/admin/src/components/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
13 |
18 |
19 |
20 |
21 |
22 |
48 |
108 |
--------------------------------------------------------------------------------
/admin/build/utils.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const path = require('path')
3 | const config = require('../config')
4 | const ExtractTextPlugin = require('extract-text-webpack-plugin')
5 | const pkg = require('../package.json')
6 |
7 | exports.assetsPath = function (_path) {
8 | const assetsSubDirectory = process.env.NODE_ENV === 'production'
9 | ? config.build.assetsSubDirectory
10 | : config.dev.assetsSubDirectory
11 | return path.posix.join(assetsSubDirectory, _path)
12 | }
13 |
14 | exports.cssLoaders = function (options) {
15 | options = options || {}
16 |
17 | const cssLoader = {
18 | loader: 'css-loader',
19 | options: {
20 | sourceMap: options.sourceMap
21 | }
22 | }
23 |
24 | var postcssLoader = {
25 | loader: 'postcss-loader',
26 | options: {
27 | sourceMap: options.sourceMap
28 | }
29 | }
30 |
31 | // generate loader string to be used with extract text plugin
32 | function generateLoaders (loader, loaderOptions) {
33 | const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
34 | if (loader) {
35 | loaders.push({
36 | loader: loader + '-loader',
37 | options: Object.assign({}, loaderOptions, {
38 | sourceMap: options.sourceMap
39 | })
40 | })
41 | }
42 |
43 | // Extract CSS when that option is specified
44 | // (which is the case during production build)
45 | if (options.extract) {
46 | return ExtractTextPlugin.extract({
47 | use: loaders,
48 | fallback: 'vue-style-loader'
49 | })
50 | } else {
51 | return ['vue-style-loader'].concat(loaders)
52 | }
53 | }
54 |
55 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html
56 | return {
57 | css: generateLoaders(),
58 | postcss: generateLoaders(),
59 | less: generateLoaders('less'),
60 | sass: generateLoaders('sass', { indentedSyntax: true }),
61 | scss: generateLoaders('sass'),
62 | stylus: generateLoaders('stylus'),
63 | styl: generateLoaders('stylus')
64 | }
65 | }
66 |
67 | // Generate loaders for standalone style files (outside of .vue)
68 | exports.styleLoaders = function (options) {
69 | const output = []
70 | const loaders = exports.cssLoaders(options)
71 | for (const extension in loaders) {
72 | const loader = loaders[extension]
73 | output.push({
74 | test: new RegExp('\\.' + extension + '$'),
75 | use: loader
76 | })
77 | }
78 | return output
79 | }
80 |
81 | exports.createNotifierCallback = function () {
82 | const notifier = require('node-notifier')
83 |
84 | return (severity, errors) => {
85 | if (severity !== 'error') {
86 | return
87 | }
88 | const error = errors[0]
89 |
90 | const filename = error.file && error.file.split('!').pop()
91 | notifier.notify({
92 | title: pkg.name,
93 | message: severity + ': ' + error.name,
94 | subtitle: filename || '',
95 | icon: path.join(__dirname, 'logo.png')
96 | })
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/front2/build/utils.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const path = require('path')
3 | const config = require('../config')
4 | const ExtractTextPlugin = require('extract-text-webpack-plugin')
5 | const pkg = require('../package.json')
6 |
7 | exports.assetsPath = function (_path) {
8 | const assetsSubDirectory = process.env.NODE_ENV === 'production'
9 | ? config.build.assetsSubDirectory
10 | : config.dev.assetsSubDirectory
11 | return path.posix.join(assetsSubDirectory, _path)
12 | }
13 |
14 | exports.cssLoaders = function (options) {
15 | options = options || {}
16 |
17 | const cssLoader = {
18 | loader: 'css-loader',
19 | options: {
20 | sourceMap: options.sourceMap
21 | }
22 | }
23 |
24 | var postcssLoader = {
25 | loader: 'postcss-loader',
26 | options: {
27 | sourceMap: options.sourceMap
28 | }
29 | }
30 |
31 | // generate loader string to be used with extract text plugin
32 | function generateLoaders (loader, loaderOptions) {
33 | const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
34 | if (loader) {
35 | loaders.push({
36 | loader: loader + '-loader',
37 | options: Object.assign({}, loaderOptions, {
38 | sourceMap: options.sourceMap
39 | })
40 | })
41 | }
42 |
43 | // Extract CSS when that option is specified
44 | // (which is the case during production build)
45 | if (options.extract) {
46 | return ExtractTextPlugin.extract({
47 | use: loaders,
48 | fallback: 'vue-style-loader'
49 | })
50 | } else {
51 | return ['vue-style-loader'].concat(loaders)
52 | }
53 | }
54 |
55 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html
56 | return {
57 | css: generateLoaders(),
58 | postcss: generateLoaders(),
59 | less: generateLoaders('less'),
60 | sass: generateLoaders('sass', { indentedSyntax: true }),
61 | scss: generateLoaders('sass'),
62 | stylus: generateLoaders('stylus'),
63 | styl: generateLoaders('stylus')
64 | }
65 | }
66 |
67 | // Generate loaders for standalone style files (outside of .vue)
68 | exports.styleLoaders = function (options) {
69 | const output = []
70 | const loaders = exports.cssLoaders(options)
71 | for (const extension in loaders) {
72 | const loader = loaders[extension]
73 | output.push({
74 | test: new RegExp('\\.' + extension + '$'),
75 | use: loader
76 | })
77 | }
78 | return output
79 | }
80 |
81 | exports.createNotifierCallback = function () {
82 | const notifier = require('node-notifier')
83 |
84 | return (severity, errors) => {
85 | if (severity !== 'error') {
86 | return
87 | }
88 | const error = errors[0]
89 |
90 | const filename = error.file && error.file.split('!').pop()
91 | notifier.notify({
92 | title: pkg.name,
93 | message: severity + ': ' + error.name,
94 | subtitle: filename || '',
95 | icon: path.join(__dirname, 'logo.png')
96 | })
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/admin/config/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // Template version: 1.2.4
3 | // see http://vuejs-templates.github.io/webpack for documentation.
4 |
5 | const path = require('path')
6 |
7 | module.exports = {
8 | dev: {
9 |
10 | // Paths
11 | assetsSubDirectory: 'static',
12 | assetsPublicPath: '/',
13 | proxyTable: {
14 | '/api': {
15 | target: 'http://127.0.0.1:3000/',
16 | changeOrigin: true,
17 | pathRewrite: {
18 | '^/api': '/'
19 | }
20 | }
21 | },
22 |
23 | // Various Dev Server settings
24 | host: 'localhost', // can be overwritten by process.env.HOST
25 | port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
26 | autoOpenBrowser: false,
27 | errorOverlay: true,
28 | notifyOnErrors: true,
29 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
30 |
31 | // Use Eslint Loader?
32 | // If true, your code will be linted during bundling and
33 | // linting errors and warnings will be shown in the console.
34 | useEslint: true,
35 | // If true, eslint errors and warnings will also be shown in the error overlay
36 | // in the browser.
37 | showEslintErrorsInOverlay: false,
38 |
39 | /**
40 | * Source Maps
41 | */
42 |
43 | // https://webpack.js.org/configuration/devtool/#development
44 | devtool: 'eval-source-map',
45 |
46 | // If you have problems debugging vue-files in devtools,
47 | // set this to false - it *may* help
48 | // https://vue-loader.vuejs.org/en/options.html#cachebusting
49 | cacheBusting: true,
50 |
51 | // CSS Sourcemaps off by default because relative paths are "buggy"
52 | // with this option, according to the CSS-Loader README
53 | // (https://github.com/webpack/css-loader#sourcemaps)
54 | // In our experience, they generally work as expected,
55 | // just be aware of this issue when enabling this option.
56 | cssSourceMap: false,
57 | },
58 |
59 | build: {
60 | // Template for index.html
61 | index: path.resolve(__dirname, '../dist/index.html'),
62 |
63 | // Paths
64 | assetsRoot: path.resolve(__dirname, '../dist'),
65 | assetsSubDirectory: 'static',
66 | assetsPublicPath: '/',
67 |
68 | /**
69 | * Source Maps
70 | */
71 |
72 | productionSourceMap: true,
73 | // https://webpack.js.org/configuration/devtool/#production
74 | devtool: '#source-map',
75 |
76 | // Gzip off by default as many popular static hosts such as
77 | // Surge or Netlify already gzip all static assets for you.
78 | // Before setting to `true`, make sure to:
79 | // npm install --save-dev compression-webpack-plugin
80 | productionGzip: false,
81 | productionGzipExtensions: ['js', 'css'],
82 |
83 | // Run the build command with an extra argument to
84 | // View the bundle analyzer report after build finishes:
85 | // `npm run build --report`
86 | // Set to `true` or `false` to always turn it on or off
87 | bundleAnalyzerReport: process.env.npm_config_report
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/front2/config/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // Template version: 1.2.4
3 | // see http://vuejs-templates.github.io/webpack for documentation.
4 |
5 | const path = require('path')
6 |
7 | module.exports = {
8 | dev: {
9 |
10 | // Paths
11 | assetsSubDirectory: 'static',
12 | assetsPublicPath: '/',
13 | proxyTable: {
14 | '/api': {
15 | target: 'http://127.0.0.1:3000/',
16 | changeOrigin: true,
17 | pathRewrite: {
18 | '^/api': '/'
19 | }
20 | }
21 | },
22 |
23 | // Various Dev Server settings
24 | host: 'localhost', // can be overwritten by process.env.HOST
25 | port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
26 | autoOpenBrowser: false,
27 | errorOverlay: true,
28 | notifyOnErrors: true,
29 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
30 |
31 | // Use Eslint Loader?
32 | // If true, your code will be linted during bundling and
33 | // linting errors and warnings will be shown in the console.
34 | useEslint: true,
35 | // If true, eslint errors and warnings will also be shown in the error overlay
36 | // in the browser.
37 | showEslintErrorsInOverlay: false,
38 |
39 | /**
40 | * Source Maps
41 | */
42 |
43 | // https://webpack.js.org/configuration/devtool/#development
44 | devtool: 'eval-source-map',
45 |
46 | // If you have problems debugging vue-files in devtools,
47 | // set this to false - it *may* help
48 | // https://vue-loader.vuejs.org/en/options.html#cachebusting
49 | cacheBusting: true,
50 |
51 | // CSS Sourcemaps off by default because relative paths are "buggy"
52 | // with this option, according to the CSS-Loader README
53 | // (https://github.com/webpack/css-loader#sourcemaps)
54 | // In our experience, they generally work as expected,
55 | // just be aware of this issue when enabling this option.
56 | cssSourceMap: false,
57 | },
58 |
59 | build: {
60 | // Template for index.html
61 | index: path.resolve(__dirname, '../dist/index.html'),
62 |
63 | // Paths
64 | assetsRoot: path.resolve(__dirname, '../dist'),
65 | assetsSubDirectory: 'static',
66 | assetsPublicPath: '/',
67 |
68 | /**
69 | * Source Maps
70 | */
71 |
72 | productionSourceMap: true,
73 | // https://webpack.js.org/configuration/devtool/#production
74 | devtool: '#source-map',
75 |
76 | // Gzip off by default as many popular static hosts such as
77 | // Surge or Netlify already gzip all static assets for you.
78 | // Before setting to `true`, make sure to:
79 | // npm install --save-dev compression-webpack-plugin
80 | productionGzip: false,
81 | productionGzipExtensions: ['js', 'css'],
82 |
83 | // Run the build command with an extra argument to
84 | // View the bundle analyzer report after build finishes:
85 | // `npm run build --report`
86 | // Set to `true` or `false` to always turn it on or off
87 | bundleAnalyzerReport: process.env.npm_config_report
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/front2/src/assets/css/reset.css:
--------------------------------------------------------------------------------
1 | /**********************************/
2 | /* RESET.CSS */
3 | /**********************************/
4 |
5 | * {
6 | margin: 0;
7 | padding: 0;
8 | -webkit-text-size-adjust: none;
9 | }
10 |
11 | label {
12 | cursor: pointer;
13 | }
14 |
15 | a {
16 | margin: 0;
17 | padding: 0;
18 | vertical-align: baseline;
19 | background: transparent;
20 | text-decoration: none;
21 | color: #000;
22 | }
23 |
24 | table {
25 | border-collapse: collapse;
26 | border-spacing: 0;
27 | }
28 |
29 | td, td img {
30 | vertical-align: top;
31 | }
32 |
33 | input, select, button, textarea {
34 | margin: 0;
35 | font-size: 100%;
36 | }
37 |
38 | input[type="checkbox"] {
39 | vertical-align: bottom;
40 | }
41 |
42 | input[type="radio"] {
43 | vertical-align: text-bottom;
44 | }
45 |
46 | sub {
47 | vertical-align: sub;
48 | font-size: smaller;
49 | }
50 |
51 | sup {
52 | vertical-align: super;
53 | font-size: smaller;
54 | }
55 |
56 | /*****************************************************************************************/
57 | html, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre,
58 | a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp,
59 | small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li,
60 | fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, input {
61 | border: 0;
62 | outline: 0;
63 | font-size: 100%;
64 | vertical-align: baseline;
65 | background: transparent;
66 | font-family: 'Roboto', sans-serif;
67 | }
68 |
69 | body {
70 | font-size: 14px;
71 | font-family: 'Roboto', sans-serif;
72 | }
73 |
74 | button {
75 | border: none;
76 | padding: 0;
77 | font-size: 0;
78 | line-height: 0;
79 | background: none;
80 | cursor: pointer;
81 | }
82 |
83 | body {
84 | line-height: 1;
85 | }
86 |
87 | ol, ul {
88 | list-style: none;
89 | }
90 |
91 | blockquote, q {
92 | quotes: none;
93 | }
94 |
95 | blockquote:before, blockquote:after,
96 | q:before, q:after {
97 | content: '';
98 | }
99 |
100 | /* remember to define focus styles! */
101 | :focus {
102 | outline: 0;
103 | }
104 |
105 | /* remember to highlight inserts somehow! */
106 | ins {
107 | text-decoration: none;
108 | }
109 |
110 | del {
111 | text-decoration: line-through;
112 | }
113 |
114 | /* tables still need 'cellspacing="0"' in the markup */
115 | table {
116 | border-collapse: collapse;
117 | border-spacing: 0;
118 | }
119 |
120 | /*------------------------------------------------------------------*/
121 | img {
122 | line-height: 0;
123 | font-size: 0;
124 | }
125 |
126 | menu {
127 | padding: 0;
128 | margin: 0;
129 | }
130 |
131 | .clearfix:before, .clearfix:after {
132 | content: "\0020";
133 | display: block;
134 | height: 0;
135 | visibility: hidden;
136 | }
137 |
138 | .clearfix:after {
139 | clear: both;
140 | }
141 |
142 | .clearfix {
143 | zoom: 1;
144 | }
145 |
146 | /**********************************/
147 | /* END RESET.CSS */
148 | /**********************************/
149 |
--------------------------------------------------------------------------------
/front2/src/assets/js/main.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Affix
3 | * Nav menu mobile
4 | /*/
5 | /* ***************** start document load **********************/
6 | $(document).ready(function() {
7 | "use strict";
8 | /*
9 | |--------------------------------------------------------------------------
10 | | Affix
11 | |--------------------------------------------------------------------------
12 | |
13 | |
14 | |
15 | */
16 | $('#myAffix').affix({
17 | offset: {
18 | top: 100,
19 | bottom: function() {
20 | return (this.bottom = $('.footer').outerHeight(true))
21 | }
22 | }
23 | });
24 | /* header select city */
25 | $('.weather__city__list ul li').on('click', function(e) {
26 | e.preventDefault();
27 |
28 | $(this).siblings("li").removeClass("active");
29 | $(this).removeClass('active').addClass('active');
30 |
31 | var text = $(this).find("a").html();
32 | $(".weather__city").find('em').html(text);
33 | return false;
34 | });
35 | /* end header select city */
36 | });
37 | /* ***************** end document load *********************/
38 | /* ************** start document resize ********************/
39 | $(window).resize(function() {
40 | "use strict";
41 | var height = 0;
42 | var autoHeight1 = $('.col-img_auto-height');
43 | var autoHeight2 = $('.col-border_auto-height');
44 | var autoHeight3 = $('.col-border_auto-height-small');
45 | $(autoHeight1).css('height', 'auto');
46 | autoHeight1.each(function() {
47 | if ($(this).height() > height) {
48 | height = $(this).height();
49 | }
50 | });
51 | autoHeight1.css('height', height);
52 |
53 | $(autoHeight2).css('height', 'auto');
54 | autoHeight2.each(function() {
55 |
56 | if ($(this).height() > height) {
57 | height = $(this).height();
58 | }
59 | });
60 | autoHeight2.css('height', height + 25);
61 |
62 | $(autoHeight3).css('height', 'auto');
63 | autoHeight3.each(function() {
64 |
65 | if ($(this).height() > height) {
66 | height = $(this).height();
67 | }
68 | });
69 | autoHeight3.css('height', height + 25);
70 | }).resize();
71 | /* **************** end document resize ********************/
72 | $(function() {
73 | "use strict";
74 | /*
75 | |--------------------------------------------------------------------------
76 | | Nav menu mobile
77 | |--------------------------------------------------------------------------
78 | |
79 | |
80 | |
81 | */
82 | var $menu = $(".overlapblackbg, .slideLeft");
83 | var $wsmenucontent = $(".wsmenucontent");
84 | var openMenu = function() {
85 | $($menu).removeClass("menuclose").addClass("menuopen")
86 | };
87 | var closeMenu = function() {
88 | $($menu).removeClass("menuopen").addClass("menuclose")
89 | };
90 | $("#navToggle").on('click', function() {
91 | if ($wsmenucontent.hasClass("menuopen")) {
92 | $(closeMenu)
93 | } else {
94 | $(openMenu)
95 | }
96 | return false;
97 | });
98 | $wsmenucontent.on('click', function() {
99 | if ($wsmenucontent.hasClass("menuopen")) {
100 | $(closeMenu)
101 | }
102 | return false;
103 | });
104 | $("#navToggle,.overlapblackbg").on('click', function() {
105 | $(".wsmenucontainer").toggleClass("mrginleft");
106 | return false;
107 | });
108 | $(".wsmenu-list li").has(".wsmenu-submenu, .wsmenu-submenu-sub, .wsmenu-submenu-sub-sub").prepend('');
109 | $(".wsmenu-list li").has(".megamenu").prepend('');
110 | $(".wsmenu-mobile").on('click', function() {
111 | $(".wsmenu-list").slideToggle("slow");
112 | return false;
113 | });
114 | $(".wsmenu-click").on('click', function() {
115 | $(this).siblings(".wsmenu-submenu").slideToggle("slow");
116 | $(this).children(".wsmenu-arrow").toggleClass("wsmenu-rotate");
117 | $(this).siblings(".wsmenu-submenu-sub").slideToggle("slow");
118 | $(this).siblings(".wsmenu-submenu-sub-sub").slideToggle("slow");
119 | $(this).siblings(".megamenu").slideToggle("slow");
120 | return false;
121 | });
122 | });
--------------------------------------------------------------------------------
/admin/src/components/Login.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
后台登录
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | 登录
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
82 |
83 |
125 |
--------------------------------------------------------------------------------
/server/controllers/type.js:
--------------------------------------------------------------------------------
1 | const Model = require('../lib/mysql.js');
2 | const createToken = require('../token/createToken.js');
3 | const moment = require('moment')
4 | class TypeController{
5 | //用户登录
6 | static async createType(ctx){
7 | //es6 解构
8 | //这里解构需要和 ctx.request.body 的对象属性相同
9 | const { typeName } = ctx.request.body;
10 | let time = moment().format('YYYY-MM-DD HH:mm')
11 | if(!typeName){
12 | ctx.jsonReturn({
13 | code:1,
14 | msg:'栏目不能为空'
15 | })
16 | }
17 | await Model.selectTypeModelByType(typeName)
18 | .then(seleInfo=>{
19 | var selectInfoRes = JSON.parse(JSON.stringify(seleInfo))
20 |
21 | if(selectInfoRes.length > 0){
22 | ctx.jsonReturn({
23 | code:1,
24 | msg:'添加失败,该栏目已存在'
25 | })
26 | }else{
27 | let inserInfo = Model.addTypeModel([typeName,time])
28 | if(inserInfo){
29 | ctx.jsonReturn({
30 | code:2,
31 | msg:'添加栏目成功'
32 | })
33 | }else{
34 | ctx.jsonReturn({
35 | code:1,
36 | msg:'添加栏目失败'
37 | })
38 | }
39 | }
40 | }).catch(err=>{
41 | ctx.jsonReturn({
42 | code:1,
43 | msg:'添加失败,服务器异常'
44 | })
45 | })
46 | }
47 | static async selectTypeAll(ctx){
48 | await Model.selectTypeAllModel()
49 | .then(res=>{
50 | var selectAllInfo = JSON.parse(JSON.stringify(res))
51 | if(selectAllInfo.length > 0){
52 | ctx.jsonReturn({
53 | code:2,
54 | data:{
55 | list:selectAllInfo
56 | },
57 | msg:'ok'
58 | })
59 | }else{
60 | ctx.jsonReturn({
61 | code:1,
62 | data:{
63 | list:[]
64 | },
65 | msg:'err'
66 | })
67 | }
68 | }).catch(err=>{
69 | ctx.jsonReturn({
70 | code:1,
71 | data:{
72 | list:[]
73 | },
74 | msg:err
75 | })
76 | })
77 |
78 | }
79 | static async delectTypeById (ctx){
80 | const {id} = ctx.request.body;
81 | if(!id || isNaN(id)){
82 | ctx.jsonReturn({
83 | code:1,
84 | data:[],
85 | msg:'id err'
86 | })
87 | }else{
88 | await Model.delTypeByIdModel(id)
89 | .then(res=>{
90 | console.log( res );
91 | if(res){
92 | ctx.jsonReturn({
93 | code:2,
94 | msg:'删除成功'
95 | })
96 | }else{
97 | ctx.jsonReturn({
98 | code:1,
99 | msg:'删除失败'
100 | })
101 | }
102 | }).catch(err=>{
103 | ctx.jsonReturn({
104 | code:1,
105 | msg:'删除失败,服务器异常'
106 | })
107 | })
108 | }
109 | }
110 | static async editTypeById(ctx){
111 | const { typeName,id } = ctx.request.body;
112 | if(!id || isNaN(id)){
113 | ctx.jsonReturn({
114 | code:1,
115 | msg:'id err'
116 | })
117 | }
118 | let time = moment().format('YYYY-MM-DD HH:mm')
119 | await Model.editTypeByIdModel([typeName,time,id])
120 | .then(res=>{
121 | if(res){
122 | ctx.jsonReturn({
123 | code:2,
124 | msg:'更新栏目成功'
125 | })
126 | }else{
127 | ctx.jsonReturn({
128 | code:1,
129 | msg:'更新栏目失败'
130 | })
131 | }
132 | }).catch(err=>{
133 | ctx.jsonReturn({
134 | code:1,
135 | msg:'服务异常,更新失败'
136 | })
137 | })
138 | }
139 | }
140 | module.exports = TypeController;
--------------------------------------------------------------------------------
/admin/src/components/Article.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
28 | 点击上传
29 | 只能上传jpg/png文件,且不超过500kb
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | 添 加
43 |
44 |
45 |
46 |
47 |
48 |
145 |
146 |
155 |
--------------------------------------------------------------------------------
/front2/src/components/Search.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
18 |
19 |
20 |
21 | -
22 |
23 | {{item.comment}}
24 |
25 |
26 | -
27 |
28 | {{item.consult}}
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
搜索不到您想要的内容,换别的关键字尝试下!
41 |
42 |
43 |
44 | Load more
45 |
48 |
49 |
50 |
我可是有底线的
51 |
52 |
53 |
54 |
55 |
56 |
91 |
119 |
--------------------------------------------------------------------------------
/admin/build/webpack.prod.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const path = require('path')
3 | const utils = require('./utils')
4 | const webpack = require('webpack')
5 | const config = require('../config')
6 | const merge = require('webpack-merge')
7 | const baseWebpackConfig = require('./webpack.base.conf')
8 | const CopyWebpackPlugin = require('copy-webpack-plugin')
9 | const HtmlWebpackPlugin = require('html-webpack-plugin')
10 | const ExtractTextPlugin = require('extract-text-webpack-plugin')
11 | const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
12 |
13 | const env = require('../config/prod.env')
14 |
15 | const webpackConfig = merge(baseWebpackConfig, {
16 | module: {
17 | rules: utils.styleLoaders({
18 | sourceMap: config.build.productionSourceMap,
19 | extract: true,
20 | usePostCSS: true
21 | })
22 | },
23 | devtool: config.build.productionSourceMap ? config.build.devtool : false,
24 | output: {
25 | path: config.build.assetsRoot,
26 | filename: utils.assetsPath('js/[name].[chunkhash].js'),
27 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
28 | },
29 | plugins: [
30 | // http://vuejs.github.io/vue-loader/en/workflow/production.html
31 | new webpack.DefinePlugin({
32 | 'process.env': env
33 | }),
34 | // UglifyJs do not support ES6+, you can also use babel-minify for better treeshaking: https://github.com/babel/minify
35 | new webpack.optimize.UglifyJsPlugin({
36 | compress: {
37 | warnings: false
38 | },
39 | sourceMap: config.build.productionSourceMap,
40 | parallel: true
41 | }),
42 | // extract css into its own file
43 | new ExtractTextPlugin({
44 | filename: utils.assetsPath('css/[name].[contenthash].css'),
45 | // set the following option to `true` if you want to extract CSS from
46 | // codesplit chunks into this main css file as well.
47 | // This will result in *all* of your app's CSS being loaded upfront.
48 | allChunks: false,
49 | }),
50 | // Compress extracted CSS. We are using this plugin so that possible
51 | // duplicated CSS from different components can be deduped.
52 | new OptimizeCSSPlugin({
53 | cssProcessorOptions: config.build.productionSourceMap
54 | ? { safe: true, map: { inline: false } }
55 | : { safe: true }
56 | }),
57 | // generate dist index.html with correct asset hash for caching.
58 | // you can customize output by editing /index.html
59 | // see https://github.com/ampedandwired/html-webpack-plugin
60 | new HtmlWebpackPlugin({
61 | filename: config.build.index,
62 | template: 'index.html',
63 | inject: true,
64 | minify: {
65 | removeComments: true,
66 | collapseWhitespace: true,
67 | removeAttributeQuotes: true
68 | // more options:
69 | // https://github.com/kangax/html-minifier#options-quick-reference
70 | },
71 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin
72 | chunksSortMode: 'dependency'
73 | }),
74 | // keep module.id stable when vender modules does not change
75 | new webpack.HashedModuleIdsPlugin(),
76 | // enable scope hoisting
77 | new webpack.optimize.ModuleConcatenationPlugin(),
78 | // split vendor js into its own file
79 | new webpack.optimize.CommonsChunkPlugin({
80 | name: 'vendor',
81 | minChunks: function (module) {
82 | // any required modules inside node_modules are extracted to vendor
83 | return (
84 | module.resource &&
85 | /\.js$/.test(module.resource) &&
86 | module.resource.indexOf(
87 | path.join(__dirname, '../node_modules')
88 | ) === 0
89 | )
90 | }
91 | }),
92 | // extract webpack runtime and module manifest to its own file in order to
93 | // prevent vendor hash from being updated whenever app bundle is updated
94 | new webpack.optimize.CommonsChunkPlugin({
95 | name: 'manifest',
96 | minChunks: Infinity
97 | }),
98 | // This instance extracts shared chunks from code splitted chunks and bundles them
99 | // in a separate chunk, similar to the vendor chunk
100 | // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
101 | new webpack.optimize.CommonsChunkPlugin({
102 | name: 'app',
103 | async: 'vendor-async',
104 | children: true,
105 | minChunks: 3
106 | }),
107 |
108 | // copy custom static assets
109 | new CopyWebpackPlugin([
110 | {
111 | from: path.resolve(__dirname, '../static'),
112 | to: config.build.assetsSubDirectory,
113 | ignore: ['.*']
114 | }
115 | ])
116 | ]
117 | })
118 |
119 | if (config.build.productionGzip) {
120 | const CompressionWebpackPlugin = require('compression-webpack-plugin')
121 |
122 | webpackConfig.plugins.push(
123 | new CompressionWebpackPlugin({
124 | asset: '[path].gz[query]',
125 | algorithm: 'gzip',
126 | test: new RegExp(
127 | '\\.(' +
128 | config.build.productionGzipExtensions.join('|') +
129 | ')$'
130 | ),
131 | threshold: 10240,
132 | minRatio: 0.8
133 | })
134 | )
135 | }
136 |
137 | if (config.build.bundleAnalyzerReport) {
138 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
139 | webpackConfig.plugins.push(new BundleAnalyzerPlugin())
140 | }
141 |
142 | module.exports = webpackConfig
143 |
--------------------------------------------------------------------------------
/front2/build/webpack.prod.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const path = require('path')
3 | const utils = require('./utils')
4 | const webpack = require('webpack')
5 | const config = require('../config')
6 | const merge = require('webpack-merge')
7 | const baseWebpackConfig = require('./webpack.base.conf')
8 | const CopyWebpackPlugin = require('copy-webpack-plugin')
9 | const HtmlWebpackPlugin = require('html-webpack-plugin')
10 | const ExtractTextPlugin = require('extract-text-webpack-plugin')
11 | const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
12 |
13 | const env = require('../config/prod.env')
14 |
15 | const webpackConfig = merge(baseWebpackConfig, {
16 | module: {
17 | rules: utils.styleLoaders({
18 | sourceMap: config.build.productionSourceMap,
19 | extract: true,
20 | usePostCSS: true
21 | })
22 | },
23 | devtool: config.build.productionSourceMap ? config.build.devtool : false,
24 | output: {
25 | path: config.build.assetsRoot,
26 | filename: utils.assetsPath('js/[name].[chunkhash].js'),
27 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
28 | },
29 | plugins: [
30 | // http://vuejs.github.io/vue-loader/en/workflow/production.html
31 | new webpack.DefinePlugin({
32 | 'process.env': env
33 | }),
34 | // UglifyJs do not support ES6+, you can also use babel-minify for better treeshaking: https://github.com/babel/minify
35 | new webpack.optimize.UglifyJsPlugin({
36 | compress: {
37 | warnings: false
38 | },
39 | sourceMap: config.build.productionSourceMap,
40 | parallel: true
41 | }),
42 | // extract css into its own file
43 | new ExtractTextPlugin({
44 | filename: utils.assetsPath('css/[name].[contenthash].css'),
45 | // set the following option to `true` if you want to extract CSS from
46 | // codesplit chunks into this main css file as well.
47 | // This will result in *all* of your app's CSS being loaded upfront.
48 | allChunks: false,
49 | }),
50 | // Compress extracted CSS. We are using this plugin so that possible
51 | // duplicated CSS from different components can be deduped.
52 | new OptimizeCSSPlugin({
53 | cssProcessorOptions: config.build.productionSourceMap
54 | ? { safe: true, map: { inline: false } }
55 | : { safe: true }
56 | }),
57 | // generate dist index.html with correct asset hash for caching.
58 | // you can customize output by editing /index.html
59 | // see https://github.com/ampedandwired/html-webpack-plugin
60 | new HtmlWebpackPlugin({
61 | filename: config.build.index,
62 | template: 'index.html',
63 | inject: true,
64 | minify: {
65 | removeComments: true,
66 | collapseWhitespace: true,
67 | removeAttributeQuotes: true
68 | // more options:
69 | // https://github.com/kangax/html-minifier#options-quick-reference
70 | },
71 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin
72 | chunksSortMode: 'dependency'
73 | }),
74 | // keep module.id stable when vender modules does not change
75 | new webpack.HashedModuleIdsPlugin(),
76 | // enable scope hoisting
77 | new webpack.optimize.ModuleConcatenationPlugin(),
78 | // split vendor js into its own file
79 | new webpack.optimize.CommonsChunkPlugin({
80 | name: 'vendor',
81 | minChunks: function (module) {
82 | // any required modules inside node_modules are extracted to vendor
83 | return (
84 | module.resource &&
85 | /\.js$/.test(module.resource) &&
86 | module.resource.indexOf(
87 | path.join(__dirname, '../node_modules')
88 | ) === 0
89 | )
90 | }
91 | }),
92 | // extract webpack runtime and module manifest to its own file in order to
93 | // prevent vendor hash from being updated whenever app bundle is updated
94 | new webpack.optimize.CommonsChunkPlugin({
95 | name: 'manifest',
96 | minChunks: Infinity
97 | }),
98 | // This instance extracts shared chunks from code splitted chunks and bundles them
99 | // in a separate chunk, similar to the vendor chunk
100 | // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
101 | new webpack.optimize.CommonsChunkPlugin({
102 | name: 'app',
103 | async: 'vendor-async',
104 | children: true,
105 | minChunks: 3
106 | }),
107 |
108 | // copy custom static assets
109 | new CopyWebpackPlugin([
110 | {
111 | from: path.resolve(__dirname, '../static'),
112 | to: config.build.assetsSubDirectory,
113 | ignore: ['.*']
114 | }
115 | ])
116 | ]
117 | })
118 |
119 | if (config.build.productionGzip) {
120 | const CompressionWebpackPlugin = require('compression-webpack-plugin')
121 |
122 | webpackConfig.plugins.push(
123 | new CompressionWebpackPlugin({
124 | asset: '[path].gz[query]',
125 | algorithm: 'gzip',
126 | test: new RegExp(
127 | '\\.(' +
128 | config.build.productionGzipExtensions.join('|') +
129 | ')$'
130 | ),
131 | threshold: 10240,
132 | minRatio: 0.8
133 | })
134 | )
135 | }
136 |
137 | if (config.build.bundleAnalyzerReport) {
138 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
139 | webpackConfig.plugins.push(new BundleAnalyzerPlugin())
140 | }
141 |
142 | module.exports = webpackConfig
143 |
--------------------------------------------------------------------------------
/admin/src/components/EditArticle.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
28 | 点击上传
29 | 只能上传jpg/png文件,且不超过500kb
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | 添 加
43 |
44 |
45 |
46 |
47 |
48 |
160 |
161 |
170 |
--------------------------------------------------------------------------------
/front2/src/components/Header.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
87 |
88 |
89 |
90 |
91 |
123 |
126 |
--------------------------------------------------------------------------------
/server/lib/mysql.js:
--------------------------------------------------------------------------------
1 | var mysql = require('mysql');
2 | var config = require('../config/index.js')
3 |
4 | //定义pool池
5 | var pool = mysql.createPool({
6 | host : config.dev.database.HOST,
7 | user : config.dev.database.USERNAME,
8 | password : config.dev.database.PASSWORD,
9 | database : config.dev.database.DATABASE
10 | });
11 |
12 | let query = function( sql, values ) {
13 |
14 | return new Promise(( resolve, reject ) => {
15 | pool.getConnection(function(err, connection) {
16 | if (err) {
17 | resolve( err )
18 | } else {
19 | connection.query(sql, values, ( err, rows) => {
20 | if ( err ) {
21 | reject( err )
22 | } else {
23 | resolve( rows )
24 | }
25 | //回收pool
26 | connection.release()
27 | })
28 | }
29 | })
30 | })
31 |
32 | }
33 | //登录查询用户
34 | let dologin = function(username,password){
35 | let _sql = `select * from user where username = "${username}" and password = "${password}"`;
36 | return query(_sql)
37 | }
38 | //登录更新token
39 | let updateUserToken = function(value){
40 | let _sql = "update user set token = ? where id = ?;"
41 | return query(_sql,value)
42 | }
43 |
44 | //添加文章
45 | let addArticlModel = function(value){
46 | let _sql = "insert into article (typeid,title,tags,thumb,content,time) values(?,?,?,?,?,?)"
47 | return query(_sql,value)
48 | }
49 | //查询栏目下的文章是否存在
50 | let selectTitleById = function(title,type){
51 | let _sql = `select * from article where title = "${title}" and typeid = "${type}" `;
52 | return query(_sql)
53 | }
54 | //添加栏目
55 | let addTypeModel = function(value){
56 | let _sql = 'insert into types (type_name,time) values(?,?)'
57 | return query(_sql,value)
58 | }
59 | //根据栏目名称查询
60 | let selectTypeModelByType = function(value){
61 | let _sql = `select * from types where type_name ="${value}" `;
62 | return query(_sql)
63 | }
64 |
65 | //查询所有的栏目
66 | let selectTypeAllModel = function(){
67 | let _sql = `select * from types`;
68 | return query(_sql)
69 | }
70 | //删除栏目根据栏目id
71 | let delTypeByIdModel = function(id){
72 | let _sql = `delete from types where id = "${id}"`;
73 | return query(_sql)
74 | }
75 | let editTypeByIdModel = function(value){
76 | let _sql = "update types set type_name = ?,time = ? where id = ?";
77 | return query(_sql,value)
78 | }
79 | //获取所有文章
80 | let selectAllArticleModel = function(value){
81 | let _sql = `select * from article`;
82 | return query(_sql)
83 | }
84 |
85 | //根据id查找文章
86 | let selectArticleByIdModel = function(id){
87 | let _sql = `select * from article where id = "${id}"`;
88 | return query(_sql);
89 | }
90 |
91 | //文章编辑
92 | let updateArticleModel = function(value){
93 | let _sql = "update article set typeid = ?,title = ?,tags = ?,thumb = ? ,content = ?,time = ? where id =?"
94 | return query(_sql,value)
95 | }
96 | //文章公开和禁止切换
97 | let updateArticleStateModel = function(value){
98 | let _sql = "update article set is_public = ? where id = ?"
99 | return query(_sql,value)
100 | }
101 |
102 | //删除文章
103 | let delArticleByIdModel = function(id){
104 | let _sql = `delete from article where id = "${id}"`;
105 | return query(_sql)
106 | }
107 |
108 | //推荐文章
109 | let articleRecommendModel = function(data){
110 | let _sql = "update article set recommend = ? where id = ?"
111 | return query(_sql,data)
112 | }
113 | //设置轮播
114 | let setSliderModel = function(data){
115 | let _sql = "update article set is_slider = ? where id =?"
116 | return query(_sql,data)
117 | }
118 |
119 |
120 |
121 | //前台
122 | let selectArticleByTypeIdModel = function(tid,page){
123 | let _sql = `select * from article where typeid = "${tid}" limit ${(page-1)*8},8;`
124 | return query(_sql);
125 | }
126 |
127 | //根据tid 查询热门文章
128 | let selectArticleByTypeHotModel = function(id){
129 | let _sql = '';
130 | if(id){
131 | _sql = `SELECT * FROM article where typeid = "${id}" ORDER BY consult DESC limit 0,4`
132 | }else{
133 | _sql = `SELECT * FROM article ORDER BY consult DESC limit 0,4`
134 | }
135 | return query(_sql)
136 | }
137 |
138 | //查找推荐文章一条
139 | let getRecommendModel = function(id){
140 | let _sql = '';
141 | if(id){
142 | _sql = `SELECT * FROM article where typeid = "${id}" and recommend = 1 ORDER BY recommend DESC limit 0,1`
143 | }else{
144 | _sql = `SELECT * FROM article where recommend = 1 ORDER BY recommend DESC limit 0,1`
145 | }
146 | return query(_sql)
147 | }
148 |
149 | let updateConsultModel = function(data){
150 | let _sql = 'update article set consult = ? where id = ?'
151 | return query(_sql,data)
152 | }
153 |
154 | //查询轮播
155 | let selectSliderModel = function(){
156 | let _sql = `SELECT * FROM article where is_slider = 1 ORDER BY is_slider DESC limit 0,4`
157 | return query(_sql)
158 | }
159 | //首页列表(不包括 热门和轮播 )
160 | let homeListModel = function(page){
161 | let _sql = `SELECT * FROM article where is_slider = 0 and recommend = 0 ORDER BY time DESC limit ${(page-1)*4},4;`
162 | return query(_sql)
163 | }
164 |
165 | //首页类型 (3条输出)
166 | let homeTypeListModel = function(){
167 | let _sql = `SELECT * FROM article where is_public = 1 ORDER BY time DESC`;
168 | return query(_sql)
169 | }
170 |
171 | //首页最新文章
172 | let newArticleListModel = function(){
173 | let _sql = `SELECT * FROM article where is_public = 1 ORDER BY time DESC limit 0,3`;
174 | return query(_sql)
175 | }
176 |
177 | //搜索
178 | let searchArticleListModel = function(title,page){
179 | let _sql = `SELECT * FROM article where is_public = 1 and title like "%${title}%" ORDER BY time DESC limit ${(page-1)*12},12`;
180 | return query(_sql)
181 | }
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 | module.exports = {
194 | dologin,
195 | updateUserToken,
196 | addArticlModel,
197 | addTypeModel,
198 | selectTypeModelByType,
199 | selectTypeAllModel,
200 | delTypeByIdModel,
201 | editTypeByIdModel,
202 | selectTitleById,
203 | selectAllArticleModel,
204 | selectArticleByIdModel,
205 | updateArticleModel,
206 | updateArticleStateModel,
207 | delArticleByIdModel,
208 | selectArticleByTypeIdModel,
209 | selectArticleByTypeHotModel,
210 | articleRecommendModel,
211 | getRecommendModel,
212 | updateConsultModel,
213 | setSliderModel,
214 | selectSliderModel,
215 | homeListModel,
216 | homeTypeListModel,
217 | newArticleListModel,
218 | searchArticleListModel
219 |
220 | }
--------------------------------------------------------------------------------
/admin/src/components/Types.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
栏目管理
4 |
5 | 添加栏目
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
18 |
19 |
20 |
24 |
28 |
29 |
30 |
34 |
35 |
39 |
40 |
43 |
44 | 编辑
47 |
48 | 删除
52 |
53 |
54 |
55 |
56 |
57 |
58 |
191 |
206 |
--------------------------------------------------------------------------------
/admin/src/components/List.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
文章列表
4 |
5 |
9 |
13 |
14 |
18 |
19 |
23 |
24 |
28 |
29 |
33 |
34 |
38 |
39 |
42 |
43 | 编辑
46 | 禁止发布
49 | 取消轮播设置轮播
52 | 取消推荐推荐
56 | 删除
60 |
61 |
62 |
63 |
64 |
65 |
66 |
203 |
213 |
--------------------------------------------------------------------------------
/front2/src/components/Detail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
61 |
62 |

63 |
70 |
71 |
79 |
88 |
91 |
92 |
93 |
94 |
95 |
151 |
154 |
--------------------------------------------------------------------------------
/front2/src/assets/css/typography.css:
--------------------------------------------------------------------------------
1 | /***********************************
2 | /* GUI */
3 | /***********************************/
4 | /* extend class */
5 | .font, .headline__category, .article__text, .article__time, .projects__title__h2, .block-title__view-all, .projects__title__view-all, .twitter__header__name, .twitter__header__text, .message__time, .message__text, .message__link, .title__h1, .redaction__category, .redaction__title, .redaction__text, .redaction__time, .comments .media-middle, .comments .media-body, .current__text, .weather__temperature em, .weather__city__list li a, .exchange__name, .exchange__course, .exchange__course span {
6 | font-size: 14px;
7 | line-height: 1.42857143;
8 | font-weight: normal;
9 | font-family: 'Roboto', sans-serif;
10 | color: #4e4e4e;
11 | }
12 |
13 | .transition, .wsmenu-list > li > a::before, .thumbnail__link img, .banner__link, .nav-tabs > li > a, .share .bg, .share .bg_facebook, .share .bg_twitter, .share .bg_google, .share__link, .tags ul li a, .message__link, .btn-comment, .error__right .error__list li .link::after, .social__item .facebook, .social__item .twitter, .social__item .gplus, .weather__city__list li, .weather__city__list li a {
14 | -webkit-transition-delay: 0s;
15 | transition-delay: 0s;
16 | -webkit-transition-duration: .2s;
17 | transition-duration: .2s;
18 | -webkit-transition-timing-function: ease-in-out;
19 | transition-timing-function: ease-in-out;
20 | }
21 |
22 | .absolute-arrow, .weather__city em::before, .exchange__course span::before {
23 | position: absolute;
24 | content: '';
25 | top: 50%;
26 | right: -15px;
27 | width: 9px;
28 | height: 9px;
29 | margin-top: -7px;
30 | border-width: 2px;
31 | border-style: solid;
32 | border-color: transparent;
33 | -webkit-transform: rotate(-45deg);
34 | transform: rotate(-45deg);
35 | background-color: transparent;
36 | }
37 |
38 | /* end extend class */
39 | /* button ajax_load*/
40 | .ajax_load {
41 | position: relative;
42 | width: 128px;
43 | height: 40px;
44 | margin: 0 auto;
45 | font-family: 'Open Sans', sans-serif;
46 | font-size: 14px;
47 | line-height: 40px;
48 | text-align: center;
49 | cursor: pointer;
50 | background: #ffffff;
51 | color: #4e4e4e;
52 | }
53 |
54 | .ajax_load i {
55 | display: inline-block;
56 | -webkit-transition-delay: 0s;
57 | transition-delay: 0s;
58 | -webkit-transition-timing-function: ease-out;
59 | transition-timing-function: ease-out;
60 | -webkit-transition-property: -webkit-transform;
61 | transition-property: -webkit-transform;
62 | transition-property: transform;
63 | transition-property: transform, -webkit-transform;
64 | -webkit-transition-duration: 1.2s;
65 | transition-duration: 1.2s;
66 | }
67 |
68 | .ajax_load:hover i {
69 | -webkit-transform: rotate(720deg);
70 | transform: rotate(720deg);
71 | }
72 |
73 | svg {
74 | position: absolute;
75 | top: 0;
76 | left: 0;
77 | }
78 |
79 | svg rect, svg path, svg polyline {
80 | fill: none;
81 | stroke: #4e4e4e;
82 | stroke-width: 1;
83 | }
84 |
85 | .ajax_load:hover svg rect {
86 | stroke: #4e4e4e;
87 | }
88 |
89 | /* end button ajax_load*/
90 | /* Basic Box */
91 | svg rect {
92 | stroke-dasharray: 400, 0;
93 | -webkit-transition: all 0.8s ease-in-out;
94 | -moz-transition: all 0.8s ease-in-out;
95 | -ms-transition: all 0.8s ease-in-out;
96 | -o-transition: all 0.8s ease-in-out;
97 | }
98 |
99 | .ajax_load:hover svg rect {
100 | stroke-width: 3;
101 | stroke-dasharray: 35, 245;
102 | stroke-dashoffset: 64;
103 | -webkit-transition: all 0.8s ease-in-out;
104 | -moz-transition: all 0.8s ease-in-out;
105 | -ms-transition: all 0.8s ease-in-out;
106 | -o-transition: all 0.8s ease-in-out;
107 | }
108 |
109 | /* form hover effect */
110 | .form-control::-webkit-input-placeholder {
111 | text-indent: 10px;
112 | -webkit-transition: text-indent 0.4s ease-in;
113 | transition: text-indent 0.4s ease-in;
114 | }
115 |
116 | .form-control:focus::-webkit-input-placeholder {
117 | text-indent: 999px;
118 | }
119 |
120 | /* end form hover effect */
121 | /* yellow line in title word*/
122 | .yel_line, .yellow-line, .underscore {
123 | position: relative;
124 | }
125 |
126 | .yel_line::after, .yellow-line::after, .underscore::after {
127 | position: absolute;
128 | content: '';
129 | bottom: -2px;
130 | left: 0;
131 | background: #f38844;
132 | height: 2px;
133 | width: 30px;
134 | }
135 |
136 | /* end yellow line in title word*/
137 | /* thumbnail image hover */
138 | .thumbnail__link {
139 | position: relative;
140 | }
141 |
142 | .thumbnail__link::before {
143 | position: absolute;
144 | top: 0;
145 | left: -75%;
146 | z-index: 2;
147 | display: block;
148 | content: '';
149 | width: 50%;
150 | height: 100%;
151 | background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.3) 100%);
152 | background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.3) 100%);
153 | -webkit-transform: skewX(-25deg);
154 | transform: skewX(-25deg);
155 | }
156 |
157 | .thumbnail__link:hover::before {
158 | -webkit-animation: shine .75s;
159 | animation: shine .75s;
160 | }
161 |
162 | @-webkit-keyframes shine {
163 | 100% {
164 | left: 125%;
165 | }
166 | }
167 |
168 | @keyframes shine {
169 | 100% {
170 | left: 125%;
171 | }
172 | }
173 | /* end thumbnail image hover */
174 | .container {
175 | padding-right: 10px !important;
176 | padding-left: 10px !important;
177 | }
178 |
179 | .row {
180 | margin-right: -10px !important;
181 | margin-left: -10px !important;
182 | }
183 |
184 | .col-lg-1, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-md-1, .col-md-10, .col-md-11, .col-md-12, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-sm-1, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-xs-1, .col-xs-10, .col-xs-11, .col-xs-12, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9 {
185 | padding-right: 10px !important;
186 | padding-left: 10px !important;
187 | }
188 | /***********************************
189 | /* END GUI */
190 | /***********************************/
191 |
192 | /***********************************
193 | /* FONTS */
194 | /***********************************/
195 | /* SVG - fonts */
196 | @font-face {
197 | font-family: 'fontello';
198 | src: url("../fonts/fontello.eot?44020949");
199 | src: url("../fonts/fontello.eot?44020949#iefix") format("embedded-opentype"), url("../fonts/fontello.woff?44020949") format("woff"), url("../fonts/fontello.ttf?44020949") format("truetype");
200 | font-weight: normal;
201 | font-style: normal;
202 | }
203 |
204 | [class^="icon-"]:before, [class*=" icon-"]:before {
205 | font-family: "fontello";
206 | font-style: normal;
207 | font-weight: normal;
208 | speak: none;
209 | display: inline-block;
210 | text-decoration: inherit;
211 | width: 1em;
212 | margin-right: .2em;
213 | text-align: center;
214 | /* opacity: .8; */
215 | /* For safety - reset parent styles, that can break glyph codes*/
216 | font-variant: normal;
217 | text-transform: none;
218 | /* fix buttons height, for twitter bootstrap */
219 | line-height: 1em;
220 | /* Animation center compensation - margins should be symmetric */
221 | /* remove if not needed */
222 | margin-left: .2em;
223 | /* you can be more comfortable with increased icons size */
224 | /* font-size: 120%; */
225 | /* Font smoothing. That was taken from TWBS */
226 | -webkit-font-smoothing: antialiased;
227 | -moz-osx-font-smoothing: grayscale;
228 | /* Uncomment for 3D effect */
229 | /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
230 | }
231 |
232 | .icon-sun:before {
233 | content: '\e800';
234 | }
235 |
236 | .icon-euro:before {
237 | content: '\e801';
238 | }
239 |
240 | .icon-search:before {
241 | content: '\e802';
242 | }
243 |
244 | .icon-down-open:before {
245 | content: '\e803';
246 | }
247 |
248 | .icon-up-open:before {
249 | content: '\e804';
250 | }
251 |
252 | .icon-play:before {
253 | content: '\e805';
254 | }
255 |
256 | .icon-facebook:before {
257 | content: '\e806';
258 | }
259 |
260 | .icon-gplus:before {
261 | content: '\e807';
262 | }
263 |
264 | .icon-twitter:before {
265 | content: '\e808';
266 | }
267 |
268 | .icon-eye:before {
269 | content: '\e809';
270 | }
271 |
272 | .icon-comment-empty:before {
273 | content: '\e80a';
274 | }
275 |
276 | .icon-reply:before {
277 | content: '\e80b';
278 | }
279 |
280 | .icon-arrows-cw:before {
281 | content: '\e80c';
282 | }
283 |
284 | /* end SVG - fonts */
285 | /* fonts (в head подключен шрифт с Google-fonts) */
286 |
287 | /***********************************
288 | /* END FONTS */
289 | /***********************************/
290 |
291 |
--------------------------------------------------------------------------------
/server/controllers/front.js:
--------------------------------------------------------------------------------
1 | const Model = require('../lib/mysql.js');
2 | const moment = require('moment')
3 | class FrontController{
4 | //文章添加
5 | static async articleList(ctx){
6 | //es6 解构
7 | //这里解构需要和 ctx.request.body 的对象属性相同
8 | const { tid,page } = ctx.request.body;
9 | let time = moment().format('YYYY-MM-DD HH:mm')
10 | if(!tid || isNaN(tid)){
11 | ctx.jsonReturn({
12 | code:1,
13 | msg:'id err'
14 | })
15 | }
16 | if(!page || isNaN(page)){
17 | page = 1
18 | }
19 |
20 | await Model.selectArticleByTypeIdModel(tid,page)
21 | .then(res=>{
22 | var selectInfoRes = JSON.parse(JSON.stringify(res))
23 | if(selectInfoRes.length <= 0){
24 | ctx.jsonReturn({
25 | code:1,
26 | msg:'无数据'
27 | })
28 | }else{
29 | ctx.jsonReturn({
30 | code:2,
31 | data:{
32 | list:selectInfoRes
33 | },
34 | msg:'ok'
35 | })
36 |
37 | }
38 | })
39 | .catch(err=>{
40 | ctx.jsonReturn({
41 | code:1,
42 | msg:'添加失败,服务器异常'
43 | })
44 | })
45 |
46 | }
47 | //查询阅读数前4的文章
48 | static async getMostConstuList(ctx){
49 | const {pid} = ctx.request.body;
50 | if(!pid || isNaN(pid)){
51 | ctx.jsonReturn({
52 | code:1,
53 | msg:'pid err'
54 | })
55 | }
56 | await Model.selectArticleByTypeHotModel(pid)
57 | .then(res=>{
58 | var selectInfoRes = JSON.parse(JSON.stringify(res))
59 | if(selectInfoRes.length <= 0){
60 | ctx.jsonReturn({
61 | code:2,
62 | data:{
63 | list:[]
64 | },
65 | msg:'ok'
66 | })
67 | }else{
68 | ctx.jsonReturn({
69 | code:2,
70 | data:{
71 | list:selectInfoRes
72 | },
73 | msg:'ok'
74 | })
75 |
76 | }
77 | })
78 | }
79 | static async getRecommend(ctx){
80 | const {pid} = ctx.request.body;
81 | await Model.getRecommendModel(pid)
82 | .then(res=>{
83 | var selectInfoRes = JSON.parse(JSON.stringify(res))
84 | if(selectInfoRes.length <= 0){
85 | ctx.jsonReturn({
86 | code:2,
87 | data:{
88 | list:[]
89 | },
90 | msg:'ok'
91 | })
92 | }else{
93 | ctx.jsonReturn({
94 | code:2,
95 | data:{
96 | list:selectInfoRes
97 | },
98 | msg:'ok'
99 | })
100 |
101 | }
102 | })
103 | }
104 |
105 | //查找文章
106 | static async findArticleById(ctx){
107 | const {id} = ctx.request.body;
108 | await Model.selectArticleByIdModel(id)
109 | .then(res=>{
110 | var selectInfoRes = JSON.parse(JSON.stringify(res))
111 | if(selectInfoRes.length <= 0){
112 | ctx.jsonReturn({
113 | code:2,
114 | data:{
115 | list:[]
116 | },
117 | msg:'ok'
118 | })
119 | }else{
120 | ctx.jsonReturn({
121 | code:2,
122 | data:{
123 | list:selectInfoRes
124 | },
125 | msg:'ok'
126 | })
127 |
128 | }
129 | })
130 | }
131 | static async updateConsult(ctx){
132 | const{id,consult} = ctx.request.body;
133 |
134 | if(!id || isNaN(id)){
135 | ctx.jsonReturn({
136 | code:1,
137 | msg:'err'
138 | })
139 | }
140 | await Model.updateConsultModel([consult,id])
141 | .then(res=>{
142 | if(res){
143 | ctx.jsonReturn({
144 | code:2,
145 | msg:'ok'
146 | })
147 | }else{
148 | ctx.jsonReturn({
149 | code:1,
150 | msg:'err'
151 | })
152 | }
153 | })
154 | }
155 | //轮播查询
156 | static async selectSlider(ctx){
157 | await Model.selectSliderModel()
158 | .then(res=>{
159 | var selectInfoRes = JSON.parse(JSON.stringify(res))
160 | if(selectInfoRes.length <= 0){
161 | ctx.jsonReturn({
162 | code:2,
163 | data:{
164 | list:[]
165 | },
166 | msg:'ok'
167 | })
168 | }else{
169 | ctx.jsonReturn({
170 | code:2,
171 | data:{
172 | list:selectInfoRes
173 | },
174 | msg:'ok'
175 | })
176 |
177 | }
178 | })
179 | }
180 |
181 | static async homeList(ctx){
182 | const {page} = ctx.request.body;
183 | if(!page || isNaN(page)){
184 | page = 1
185 | }
186 | await Model.homeListModel(page)
187 | .then(res=>{
188 | var selectInfoRes = JSON.parse(JSON.stringify(res))
189 | if(selectInfoRes.length <= 0){
190 | ctx.jsonReturn({
191 | code:1,
192 |
193 | msg:'无数据'
194 | })
195 | }else{
196 | ctx.jsonReturn({
197 | code:2,
198 | data:{
199 | list:selectInfoRes
200 | },
201 | msg:'ok'
202 | })
203 |
204 | }
205 | })
206 | }
207 | //最新文章
208 | static async newList(ctx){
209 | await Model.newArticleListModel()
210 | .then(res=>{
211 | var selectInfoRes = JSON.parse(JSON.stringify(res))
212 | if(selectInfoRes.length <= 0){
213 | ctx.jsonReturn({
214 | code:1,
215 | msg:'无数据'
216 | })
217 | }else{
218 | ctx.jsonReturn({
219 | code:2,
220 | data:{
221 | list:selectInfoRes
222 | },
223 | msg:'ok'
224 | })
225 |
226 | }
227 | })
228 | }
229 | static async getTypeList(ctx){
230 | let typeListArr = await Model.selectTypeAllModel()
231 | .then(typeRes=>{
232 | var typeList = JSON.parse(JSON.stringify(typeRes))
233 | return typeList
234 | })
235 | await Model.homeTypeListModel()
236 | .then(res=>{
237 | var selectInfoRes = JSON.parse(JSON.stringify(res))
238 | if(selectInfoRes.length <= 0){
239 | ctx.jsonReturn({
240 | code:2,
241 | data:{
242 | list:[]
243 | },
244 | msg:'无数据'
245 | })
246 | }else{
247 |
248 | // [
249 | // {
250 | // type:'nodejs',
251 | // list:[]
252 | // }
253 | // ]
254 |
255 | let newList = [];
256 | typeListArr.forEach(type=>{
257 | let itemArr = {type:type.type_name,list:[],typeid:type.id};
258 | selectInfoRes.forEach(item=>{
259 | if(type.id == item.typeid){
260 | item['type_name'] = type.type_name
261 | itemArr.list.push(item)
262 | }
263 | })
264 | newList.push(itemArr)
265 | })
266 | ctx.jsonReturn({
267 | code:2,
268 | data:{
269 | list:newList
270 | },
271 | msg:'ok'
272 | })
273 |
274 | }
275 | })
276 | }
277 | static async searchArticleList(ctx){
278 | const {page,title} = ctx.request.body;
279 |
280 | if(!page || isNaN(page)){
281 | ctx.jsonReturn({
282 | code:1,
283 | msg:'err'
284 | })
285 | }
286 | await Model.searchArticleListModel(title,page)
287 | .then(res=>{
288 | var selectInfoRes = JSON.parse(JSON.stringify(res))
289 | if(selectInfoRes.length <= 0){
290 | ctx.jsonReturn({
291 | code:1,
292 | msg:'err2'
293 | })
294 | }else{
295 | ctx.jsonReturn({
296 | code:2,
297 | data:{
298 | list:selectInfoRes
299 | },
300 | msg:'ok'
301 | })
302 |
303 | }
304 | })
305 |
306 | }
307 |
308 |
309 | }
310 | module.exports = FrontController;
--------------------------------------------------------------------------------
/front2/src/components/List.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
13 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 | -
89 |
90 | {{item.comment}}
91 |
92 |
93 | -
94 |
95 | {{item.consult}}
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 | Load more
108 |
111 |
112 |
113 |
我可是有底线的
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |

127 |
128 |
Advertising
129 |
Here
130 |
Get Now
131 |
132 |
133 |
134 |
135 |
136 |
137 |
联系我
138 |
139 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
232 |
264 |
--------------------------------------------------------------------------------
/server/controllers/article.js:
--------------------------------------------------------------------------------
1 | const Model = require('../lib/mysql.js');
2 | const moment = require('moment')
3 | class ArticleController{
4 | //文章添加
5 | static async createArticle(ctx){
6 | //es6 解构
7 | //这里解构需要和 ctx.request.body 的对象属性相同
8 | const { title,content,tags,type,thumb } = ctx.request.body;
9 | let time = moment().format('YYYY-MM-DD HH:mm')
10 | if(!title){
11 | ctx.jsonReturn({
12 | code:1,
13 | msg:'标题不能为空'
14 | })
15 | }
16 | if(!content){
17 | ctx.jsonReturn({
18 | code:1,
19 | msg:'内容不能为空'
20 | })
21 | }
22 | if(!type){
23 | ctx.jsonReturn({
24 | code:1,
25 | msg:'类型不能为空'
26 | })
27 | }
28 | await Model.selectTypeAllModel()
29 | .then(res=>{
30 | var selectInfoRes = JSON.parse(JSON.stringify(res))
31 | if(selectInfoRes.length <= 0){
32 | ctx.jsonReturn({
33 | code:1,
34 | msg:'暂时无栏目,先添加栏目'
35 | })
36 | }else{
37 | var typeArr = [];
38 | selectInfoRes.forEach(function(item){
39 | typeArr.push(item.id)
40 | });
41 | function in_array(needle, haystack) {
42 | for(var i in haystack) {
43 | if(haystack[i] == needle) {
44 | return true;
45 | }
46 | }
47 | return false;
48 | }
49 | if(!in_array(type,typeArr)){
50 | ctx.jsonReturn({
51 | code:1,
52 | msg:'栏目id不合法'
53 | })
54 | }
55 | let seleInfo = Model.selectTitleById(title,type);
56 | return seleInfo;
57 | }
58 | })
59 | .then(seleInfo=>{
60 | var seIn = JSON.parse(JSON.stringify(seleInfo))
61 | if(seIn.length){
62 | ctx.jsonReturn({
63 | code:1,
64 | msg:'该栏目下已存在此文章'
65 | })
66 | }else{
67 | let addRes = Model.addArticlModel([type,title,tags,thumb,content,time])
68 | if(addRes){
69 | ctx.jsonReturn({
70 | code:2,
71 | msg:'添加文章成功'
72 | })
73 | }else{
74 | ctx.jsonReturn({
75 | code:1,
76 | msg:'失败'
77 | })
78 | }
79 | }
80 | })
81 | .catch(err=>{
82 | ctx.jsonReturn({
83 | code:1,
84 | msg:'添加失败,服务器异常'
85 | })
86 | })
87 |
88 | }
89 | static async getArticleList(ctx){
90 | let resList = await Model.selectAllArticleModel()
91 | .then(res=>{
92 | var resList = JSON.parse(JSON.stringify(res))
93 | if(resList.length == 0){
94 | ctx.jsonReturn({
95 | code:1,
96 | data:{
97 | list:[]
98 | },
99 | msg:'err'
100 | })
101 | }
102 | return resList;
103 | })
104 |
105 | await Model.selectTypeAllModel()
106 | .then(typeListres=>{
107 | var typeList = JSON.parse(JSON.stringify(typeListres))
108 | let newList = resList.map(function(item,index){
109 | typeList.forEach(function(item2,index){
110 | if(item['typeid'] == item2['id']){
111 | item['type_name'] = item2['type_name']
112 | }
113 | if(item['is_public'] == 1){
114 | item['public_state'] = '发布'
115 | }else{
116 | item['public_state'] = '未发布'
117 | }
118 | })
119 | return item;
120 | })
121 | ctx.jsonReturn({
122 | code:2,
123 | data:{
124 | list:newList
125 | },
126 | msg:'ok'
127 | })
128 | }).catch(err=>{
129 | ctx.jsonReturn({
130 | code:1,
131 | data:{
132 | list:[]
133 | },
134 | msg:'err'
135 | })
136 | })
137 |
138 | }
139 | static async getArticle(ctx){
140 | const{ id } = ctx.request.body;
141 | console.log( id );
142 | if(!id || isNaN(id)){
143 | ctx.jsonReturn({
144 | code:1,
145 | msg:'id err'
146 | })
147 | }
148 | await Model.selectArticleByIdModel(id)
149 | .then(res=>{
150 | var resList = JSON.parse(JSON.stringify(res))
151 | if(resList.length){
152 | ctx.jsonReturn({
153 | code:2,
154 | data:resList[0],
155 | msg:'ok'
156 | })
157 | }else{
158 | ctx.jsonReturn({
159 | code:1,
160 | msg:'err'
161 | })
162 | }
163 |
164 | }).catch(err=>{
165 | ctx.jsonReturn({
166 | code:1,
167 | msg:'err'
168 | })
169 | })
170 | }
171 | static async editArticle(ctx){
172 | //es6 解构
173 | //这里解构需要和 ctx.request.body 的对象属性相同
174 | const { title,content,tags,type,id,thumb } = ctx.request.body;
175 | let time = moment().format('YYYY-MM-DD HH:mm')
176 | if(!title){
177 | ctx.jsonReturn({
178 | code:1,
179 | msg:'标题不能为空'
180 | })
181 | }
182 | if(!content){
183 | ctx.jsonReturn({
184 | code:1,
185 | msg:'内容不能为空'
186 | })
187 | }
188 | if(!type){
189 | ctx.jsonReturn({
190 | code:1,
191 | msg:'类型不能为空'
192 | })
193 | }
194 | await Model.selectTypeAllModel()
195 | .then(res=>{
196 | var selectInfoRes = JSON.parse(JSON.stringify(res))
197 | if(selectInfoRes.length <= 0){
198 | ctx.jsonReturn({
199 | code:1,
200 | msg:'暂时无栏目,先添加栏目'
201 | })
202 | }else{
203 | var typeArr = [];
204 | selectInfoRes.forEach(function(item){
205 | typeArr.push(item.id)
206 | });
207 | function in_array(needle, haystack) {
208 | for(var i in haystack) {
209 | if(haystack[i] == needle) {
210 | return true;
211 | }
212 | }
213 | return false;
214 | }
215 | if(!in_array(type,typeArr)){
216 | ctx.jsonReturn({
217 | code:1,
218 | msg:'栏目id不合法'
219 | })
220 | }
221 | let seleInfo = Model.selectTitleById(title,type);
222 | return seleInfo;
223 | }
224 | })
225 | .then(seleInfo=>{
226 | var seIn = JSON.parse(JSON.stringify(seleInfo))
227 | if(seIn.length){
228 | ctx.jsonReturn({
229 | code:1,
230 | msg:'改栏目下已存在此文章'
231 | })
232 | }else{
233 | let addRes = Model.updateArticleModel([type,title,tags,thumb,content,time,id])
234 | if(addRes){
235 | ctx.jsonReturn({
236 | code:2,
237 | msg:'修改文章成功'
238 | })
239 | }else{
240 | ctx.jsonReturn({
241 | code:1,
242 | msg:'修改文章失败'
243 | })
244 | }
245 | }
246 | })
247 | .catch(err=>{
248 | ctx.jsonReturn({
249 | code:1,
250 | msg:'修改失败,服务器异常'
251 | })
252 | })
253 |
254 |
255 | }
256 | static async updateState(ctx){
257 | const{state,id} = ctx.request.body;
258 | if(!state || !id){
259 | ctx.jsonReturn({
260 | code:1,
261 | msg:'err'
262 | })
263 | }
264 | await Model.updateArticleStateModel([state,id])
265 | .then(res=>{
266 | if(res){
267 | ctx.jsonReturn({
268 | code:2,
269 | msg:'操作成功'
270 | })
271 | }else{
272 | ctx.jsonReturn({
273 | code:1,
274 | msg:'操作失败'
275 | })
276 | }
277 | }).catch(err=>{
278 | ctx.jsonReturn({
279 | code:1,
280 | msg:'操作失败:'+err
281 | })
282 | })
283 |
284 | }
285 | static async delArticleById(ctx){
286 | const{ id } = ctx.request.body;
287 | if(!id || isNaN(id)){
288 | ctx.jsonReturn({
289 | code:1,
290 | msg:'id err'
291 | })
292 | }
293 | await Model.delArticleByIdModel(id)
294 | .then(res=>{
295 | if(res){
296 | ctx.jsonReturn({
297 | code:2,
298 | msg:'删除成功'
299 | })
300 | }else{
301 | ctx.jsonReturn({
302 | code:1,
303 | msg:'删除失败'
304 | })
305 | }
306 | })
307 | }
308 | //推荐
309 | static async setRecommend(ctx){
310 | const { id,recommedid } = ctx.request.body;
311 | if(!id || isNaN(id)){
312 | ctx.jsonReturn({
313 | code:1,
314 | msg:'id err'
315 | })
316 | }
317 | await Model.articleRecommendModel([recommedid,id])
318 | .then(res=>{
319 | if(res){
320 | ctx.jsonReturn({
321 | code:2,
322 | msg:'操作成功'
323 | })
324 | }else{
325 | ctx.jsonReturn({
326 | code:1,
327 | msg:'操作失败'
328 | })
329 | }
330 | })
331 | }
332 | static async setSliderCon(ctx){
333 | const { id,slider_state } = ctx.request.body;
334 | if(!id || isNaN(id)){
335 | ctx.jsonReturn({
336 | code:1,
337 | msg:'id err'
338 | })
339 | }
340 | await Model.setSliderModel([slider_state,id])
341 | .then(res=>{
342 | if(res){
343 | ctx.jsonReturn({
344 | code:2,
345 | msg:'操作成功'
346 | })
347 | }else{
348 | ctx.jsonReturn({
349 | code:1,
350 | msg:'操作失败'
351 | })
352 | }
353 | })
354 | }
355 | }
356 | module.exports = ArticleController;
--------------------------------------------------------------------------------
评论区
90 |