diff --git a/build/vue.config.js b/build/vue.config.js new file mode 100644 index 0000000..d09b52e --- /dev/null +++ b/build/vue.config.js @@ -0,0 +1,12 @@ +var webpack = require('webpack'); + +module.exports = { + configureWebpack: { + plugins: [ + new webpack.ProvidePlugin({ + 'window.Quill': 'quill/dist/quill.js', + 'Quill': 'quill/dist/quill.js' + }), + ] + } +} diff --git a/build/webpack.base.conf.js b/build/webpack.base.conf.js index 1f4f47e..1bec590 100644 --- a/build/webpack.base.conf.js +++ b/build/webpack.base.conf.js @@ -36,21 +36,33 @@ module.exports = { alias: { 'vue$': 'vue/dist/vue.esm.js', '@': resolve('src'), - } + Views: resolve('src/views'), + Config: resolve('src/config'), + Components: resolve('src/components'), + Store: resolve('src/store'), + Router: resolve('src/router') + }, }, module: { rules: [ ...(config.dev.useEslint ? [createLintingRule()] : []), { test: /\.vue$/, + exclude: /node_modules(?!\/quill-image-drop-module|quill-image-resize-module)/, loader: 'vue-loader', options: vueLoaderConfig }, { test: /\.js$/, + exclude: /node_modules(?!\/quill-image-drop-module|quill-image-resize-module)/, loader: 'babel-loader', include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')] }, + { + test: /\.scss$/, + loaders: ['style-loader', 'css-loader', 'sass-loader'], + + }, { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'url-loader', diff --git a/build/webpack.dev.conf.js b/build/webpack.dev.conf.js index 070ae22..53e6984 100755 --- a/build/webpack.dev.conf.js +++ b/build/webpack.dev.conf.js @@ -48,6 +48,10 @@ const devWebpackConfig = merge(baseWebpackConfig, { new webpack.DefinePlugin({ 'process.env': require('../config/dev.env') }), + new webpack.ProvidePlugin({ + 'window.Quill': 'quill/dist/quill.js', + 'Quill': 'quill/dist/quill.js' + }), new webpack.HotModuleReplacementPlugin(), new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update. new webpack.NoEmitOnErrorsPlugin(), diff --git a/build/webpack.prod.conf.js b/build/webpack.prod.conf.js index 2f17259..47f3401 100644 --- a/build/webpack.prod.conf.js +++ b/build/webpack.prod.conf.js @@ -43,12 +43,16 @@ const webpackConfig = merge(baseWebpackConfig, { sourceMap: config.build.productionSourceMap, parallel: true }), + new webpack.ProvidePlugin({ + 'window.Quill': 'quill/dist/quill.js', + 'Quill': 'quill/dist/quill.js' + }), // extract css into its own file new ExtractTextPlugin({ filename: utils.assetsPath('css/[name].[contenthash].css'), // Setting the following option to `false` will not extract CSS from codesplit chunks. // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack. - // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`, + // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`, // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110 allChunks: true, }), diff --git a/config/index.js b/config/index.js index 926ab36..0377f30 100644 --- a/config/index.js +++ b/config/index.js @@ -15,7 +15,7 @@ module.exports = { // Various Dev Server settings host: 'localhost', // can be overwritten by process.env.HOST port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined - autoOpenBrowser: false, + autoOpenBrowser: true, errorOverlay: true, notifyOnErrors: true, poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- diff --git a/package.json b/package.json index 023fea3..8f0c4b1 100644 --- a/package.json +++ b/package.json @@ -14,8 +14,16 @@ "build": "node build/build.js" }, "dependencies": { + "axios": "^0.18.0", + "js-md5": "^0.7.3", + "quill": "^1.3.6", + "quill-image-drop-module": "^1.0.3", + "quill-image-extend-module": "^1.1.2", + "quill-image-resize-module": "^3.0.0", "vue": "^2.5.2", - "vue-router": "^3.0.1" + "vue-quill-editor": "^3.0.6", + "vue-router": "^3.0.1", + "vuex": "^3.0.1" }, "devDependencies": { "autoprefixer": "^7.1.2", @@ -36,7 +44,7 @@ "chromedriver": "^2.27.2", "copy-webpack-plugin": "^4.0.1", "cross-spawn": "^5.0.1", - "css-loader": "^0.28.0", + "css-loader": "^0.28.11", "eslint": "^4.15.0", "eslint-config-standard": "^10.2.1", "eslint-friendly-formatter": "^3.0.0", @@ -54,16 +62,20 @@ "jest-serializer-vue": "^0.3.0", "nightwatch": "^0.9.12", "node-notifier": "^5.1.2", + "node-sass": "^4.9.4", "optimize-css-assets-webpack-plugin": "^3.2.0", "ora": "^1.2.0", "portfinder": "^1.0.13", "postcss-import": "^11.0.0", "postcss-loader": "^2.0.8", "postcss-url": "^7.2.1", + "quill-image-extend-module": "^1.1.2", "rimraf": "^2.6.0", + "sass-loader": "^7.1.0", "selenium-server": "^3.0.1", "semver": "^5.3.0", "shelljs": "^0.7.6", + "style-loader": "^0.23.1", "uglifyjs-webpack-plugin": "^1.1.1", "url-loader": "^0.5.8", "vue-jest": "^1.0.2", diff --git a/src/App.vue b/src/App.vue index d74c648..e828af1 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,23 +1,18 @@ - - diff --git a/src/assets/css/reset.css b/src/assets/css/reset.css new file mode 100644 index 0000000..87ad942 --- /dev/null +++ b/src/assets/css/reset.css @@ -0,0 +1,118 @@ +/** + * Eric Meyer's Reset CSS v2.0 (http://meyerweb.com/eric/tools/css/reset/) + * http://cssreset.com + */ +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, +menu, nav, output, ruby, section, summary, +time, mark, audio, video, input { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font-weight: normal; + vertical-align: baseline; +} + +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, menu, nav, section { + display: block; +} + +body { + line-height: 1; +} + +blockquote, q { + quotes: none; +} + +blockquote:before, blockquote:after, +q:before, q:after { + content: none; +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +/* custom */ +a { + color: #7e8c8d; + text-decoration: none; + -webkit-backface-visibility: hidden; +} + +li { + list-style: none; +} + +::-webkit-scrollbar { + width: 5px; + height: 5px; +} + +::-webkit-scrollbar-track-piece { + background-color: rgba(0, 0, 0, 0.2); + -webkit-border-radius: 6px; +} + +::-webkit-scrollbar-thumb:vertical { + height: 5px; + background-color: rgba(125, 125, 125, 0.7); + -webkit-border-radius: 6px; +} + +::-webkit-scrollbar-thumb:horizontal { + width: 5px; + background-color: rgba(125, 125, 125, 0.7); + -webkit-border-radius: 6px; +} + +html, body { + width: 100%; +} + +body { + -webkit-text-size-adjust: none; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} +.w1200{ + max-width: 1200px; +} +.center{ + margin: 0 auto; +} +.float-left{ + float: left; +} +.float-right{ + float: right; +} +.hidden{ + display: none; +} +.router-link-exact-active{ + color: #00A7EB !important; +} +.clearbox:after,.clearbox:after{ + content: "020"; + display: block; + height: 0; + clear: both; + visibility: hidden; +} +.par20{ + padding-right: 20px; +} diff --git a/src/assets/js/bus.js b/src/assets/js/bus.js new file mode 100644 index 0000000..b0230b5 --- /dev/null +++ b/src/assets/js/bus.js @@ -0,0 +1,2 @@ +import Vue from 'vue' +export default new Vue() diff --git a/src/components/HelloWorld.vue b/src/components/HelloWorld.vue deleted file mode 100644 index 1c19f2a..0000000 --- a/src/components/HelloWorld.vue +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - diff --git a/src/components/articleDetail/index.vue b/src/components/articleDetail/index.vue new file mode 100644 index 0000000..1b26e8e --- /dev/null +++ b/src/components/articleDetail/index.vue @@ -0,0 +1,66 @@ + + + diff --git a/src/components/blogItem/index.vue b/src/components/blogItem/index.vue new file mode 100644 index 0000000..a8157b0 --- /dev/null +++ b/src/components/blogItem/index.vue @@ -0,0 +1,95 @@ + + + diff --git a/src/components/edit/index.vue b/src/components/edit/index.vue new file mode 100644 index 0000000..ea49ef7 --- /dev/null +++ b/src/components/edit/index.vue @@ -0,0 +1,165 @@ + + + diff --git a/src/components/pagination/index.vue b/src/components/pagination/index.vue new file mode 100644 index 0000000..fb962bd --- /dev/null +++ b/src/components/pagination/index.vue @@ -0,0 +1,67 @@ + + + diff --git a/src/components/quest-404.vue b/src/components/quest-404.vue new file mode 100644 index 0000000..6ee08cb --- /dev/null +++ b/src/components/quest-404.vue @@ -0,0 +1,20 @@ + + + diff --git a/src/components/success.vue b/src/components/success.vue new file mode 100644 index 0000000..3db7768 --- /dev/null +++ b/src/components/success.vue @@ -0,0 +1,37 @@ + + + diff --git a/src/components/titleBar.vue b/src/components/titleBar.vue new file mode 100644 index 0000000..8b52e52 --- /dev/null +++ b/src/components/titleBar.vue @@ -0,0 +1,31 @@ + + + diff --git a/src/config/interceptors/index.js b/src/config/interceptors/index.js new file mode 100644 index 0000000..9101dc7 --- /dev/null +++ b/src/config/interceptors/index.js @@ -0,0 +1,42 @@ +import axios from 'axios' +import server from '../server' +import utils from '../utils' +import router from 'Router/index' + +const service = axios.create({ + baseURI: server['base'], + timeout: 5000 +}) +service.interceptors.request.use( + config => { + if (utils.getStorage('token')) { + config.headers['X-Token'] = utils.getStorage('token') + config.headers['User-Type'] = utils.getStorage('userName') + } + return config + }, + error => { + return Promise.reject(error) + } +) + +service.interceptors.response.use( + response => { + return response + }, + error => { + console.log(error) + if (error.response) { + switch (error.response.status) { + case 401: + case 403: + utils.removeItem('token') + router.replace('/admin/login') + } + } + + return Promise.reject(error) + } +) + +export default service diff --git a/src/config/router.js b/src/config/router.js new file mode 100644 index 0000000..3316fcd --- /dev/null +++ b/src/config/router.js @@ -0,0 +1,8 @@ +let router = [ + {title: '网站首页', path: '/index'}, + {title: '关于我', path: '/aboutMe'}, + {title: '留言', path: '/leaveMessage'}, + {title: '最新技术', path: '/news'}, + {title: '最近一些感想', path: '/mood'} +] +export default router diff --git a/src/config/server.js b/src/config/server.js new file mode 100644 index 0000000..02e94f6 --- /dev/null +++ b/src/config/server.js @@ -0,0 +1,13 @@ +let root = 'http://localhost:3000' +export default { + 'visitor/article': `${root}/visitor/article`, + 'visitor/article/like': `${root}/visitor/article/like`, + 'user/article/delete': `${root}/user/article/delete`, + 'user/article/images': `${root}/user/article/images`, + 'images': `${root}/images/`, + 'user/article/add': `${root}/user/article/add`, + 'user/article/update': `${root}/user/article/update`, + 'visitor/article/detail': `${root}/visitor/article/detail`, + 'user/login': `${root}/user/login`, + 'base': root +} diff --git a/src/config/utils.js b/src/config/utils.js new file mode 100644 index 0000000..c99384e --- /dev/null +++ b/src/config/utils.js @@ -0,0 +1,45 @@ + +export default { + throttle (fn, delay = 250) { + let last + let timer = null + return function () { + let context = this + let args = arguments + // console.log(this) + let now = +new Date() + if (last && now < last + delay) { + clearTimeout(timer) + timer = setTimeout(() => { + fn.apply(context, args) + }, delay) + } else { + last = now + fn.apply(context, args) + } + } + }, + debounce (fn) { + let timer = null + return function () { + let context = this + let args = arguments + clearTimeout(timer) + timer = setTimeout(() => { + fn.apply(context, args) + }, 300) + } + }, + setStorage (query) { + const storage = window.localStorage + for (let key in query) { + storage[key] = query[key] + } + }, + getStorage (key) { + return window.localStorage.getItem(key) + }, + removeItem (query) { + window.localStorage.removeItem(query) + } +} diff --git a/src/main.js b/src/main.js index 417390e..1380b79 100644 --- a/src/main.js +++ b/src/main.js @@ -3,13 +3,25 @@ import Vue from 'vue' import App from './App' import router from './router' +// import axios from 'axios' +import VueQuillEditor from 'vue-quill-editor' +import 'quill/dist/quill.core.css' +import 'quill/dist/quill.snow.css' +import 'quill/dist/quill.bubble.css' +import store from 'Store/index' +import axios from 'Config/interceptors/index' + +Vue.use(VueQuillEditor) Vue.config.productionTip = false +Vue.prototype.$http = axios /* eslint-disable no-new */ new Vue({ el: '#app', router, + store, + axios, components: { App }, template: '' }) diff --git a/src/router/index.js b/src/router/index.js index 5fa7f9d..c20a58e 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -1,15 +1,73 @@ import Vue from 'vue' import Router from 'vue-router' -import HelloWorld from '@/components/HelloWorld' +// import HelloWorld from '@/components/HelloWorld' +import Layout from 'Views/layout/index.vue' +import AboutMe from 'Views/content/aboutMe/index.vue' +import Admin from 'Views/content/admin/index.vue' +import Edit from 'Components/edit' +import ArticleDetail from 'Components/articleDetail' +import Success from 'Components/success' +import Login from 'Views/content/login/index.vue' +import utils from 'Config/utils' +import Quest404 from 'Components/quest-404' Vue.use(Router) -export default new Router({ +let router = new Router({ routes: [ { path: '/', - name: 'HelloWorld', - component: HelloWorld + redirect: '/index' + }, + { + path: '/index', + component: Layout + }, + { + path: '/aboutMe', + component: AboutMe + }, + { + path: '/admin', + meta: { requiresAuth: true }, + component: Admin + }, + { + path: '/admin/edit', + meta: { requiresAuth: true }, + component: Edit + }, + { + path: '/article/detail/:id', + component: ArticleDetail + }, + { + path: '/article/success', + meta: { requiresAuth: true }, + component: Success + }, + { + path: '/admin/login', + component: Login + }, + { + path: '*', + component: Quest404 } ] }) + +router.beforeEach((to, from, next) => { + if (to.matched.some(record => record.meta.requiresAuth)) { + let token = utils.getStorage('token') + if (token === null || token === '') { + next('/admin/login') + } else { + next() + } + } else { + next() + } +}) + +export default router diff --git a/src/store/index.js b/src/store/index.js new file mode 100644 index 0000000..005091e --- /dev/null +++ b/src/store/index.js @@ -0,0 +1,22 @@ +import Vue from 'vue' +import Vuex from 'vuex' +Vue.use(Vuex) + +export default new Vuex.Store({ + state: { + userName: '', + token: '' + }, + actions: { + setStore ({commit, state}, data) { + commit('setStore', data) + } + }, + mutations: { + setStore (state, data) { + state.userName = data.userName + state.token = data.token + } + }, + getter: {} +}) diff --git a/src/views/content/aboutMe/index.vue b/src/views/content/aboutMe/index.vue new file mode 100644 index 0000000..d4d9b87 --- /dev/null +++ b/src/views/content/aboutMe/index.vue @@ -0,0 +1,14 @@ + + + diff --git a/src/views/content/admin/index.vue b/src/views/content/admin/index.vue new file mode 100644 index 0000000..ed56d80 --- /dev/null +++ b/src/views/content/admin/index.vue @@ -0,0 +1,28 @@ + + + diff --git a/src/views/content/index.vue b/src/views/content/index.vue new file mode 100644 index 0000000..014526a --- /dev/null +++ b/src/views/content/index.vue @@ -0,0 +1,29 @@ + + + diff --git a/src/views/content/likeBlog/components/likeItem.vue b/src/views/content/likeBlog/components/likeItem.vue new file mode 100644 index 0000000..fd1f404 --- /dev/null +++ b/src/views/content/likeBlog/components/likeItem.vue @@ -0,0 +1,45 @@ + + + diff --git a/src/views/content/likeBlog/index.vue b/src/views/content/likeBlog/index.vue new file mode 100644 index 0000000..5385f03 --- /dev/null +++ b/src/views/content/likeBlog/index.vue @@ -0,0 +1,18 @@ + + + diff --git a/src/views/content/login/index.vue b/src/views/content/login/index.vue new file mode 100644 index 0000000..0eb720b --- /dev/null +++ b/src/views/content/login/index.vue @@ -0,0 +1,109 @@ + + + diff --git a/src/views/content/newBlog/index.vue b/src/views/content/newBlog/index.vue new file mode 100644 index 0000000..1c97c7d --- /dev/null +++ b/src/views/content/newBlog/index.vue @@ -0,0 +1,45 @@ + + + diff --git a/src/views/footer/index.vue b/src/views/footer/index.vue new file mode 100644 index 0000000..6bf3831 --- /dev/null +++ b/src/views/footer/index.vue @@ -0,0 +1,18 @@ + + + diff --git a/src/views/header/components/navBar.vue b/src/views/header/components/navBar.vue new file mode 100644 index 0000000..8e62a5b --- /dev/null +++ b/src/views/header/components/navBar.vue @@ -0,0 +1,52 @@ + + + diff --git a/src/views/header/index.vue b/src/views/header/index.vue new file mode 100644 index 0000000..a84c615 --- /dev/null +++ b/src/views/header/index.vue @@ -0,0 +1,23 @@ + + + diff --git a/src/views/layout/index.vue b/src/views/layout/index.vue new file mode 100644 index 0000000..ef0192d --- /dev/null +++ b/src/views/layout/index.vue @@ -0,0 +1,22 @@ + + + diff --git a/test/test.html b/test/test.html new file mode 100644 index 0000000..4d0fccb --- /dev/null +++ b/test/test.html @@ -0,0 +1,59 @@ + + + + + Title + + + +
+
+
+ + + diff --git a/test/test.js b/test/test.js new file mode 100644 index 0000000..9a32c10 --- /dev/null +++ b/test/test.js @@ -0,0 +1,13 @@ +function computePage (num, pageNum, arr) { + let mid = 5 + let left = mid - num / 2 + let right = mid + num / 2 + left = left < 1 ? 1 : left + left = right > pageNum ? pageNum - 10 : left + return arr.slice(left, num) +} +let arr = [] +for (let i = 0; i < 20; i++) { + arr.push(i + 1) +} +console.log(computePage(9, 20, arr)) diff --git a/test/test2.html b/test/test2.html new file mode 100644 index 0000000..c19f5a5 --- /dev/null +++ b/test/test2.html @@ -0,0 +1,56 @@ + + + + + Title + + + +
+
+
+ + +