From 630b816c1426e35b429e700bb8f401f86336f818 Mon Sep 17 00:00:00 2001 From: ewall <1054064180@qq.com> Date: Fri, 20 Mar 2020 20:03:49 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9Ainit=20version=202.0.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .browserslistrc | 2 + .editorconfig | 5 ++ .env.development | 14 ++++ .env.production | 6 ++ .eslintignore | 4 + .eslintrc.js | 18 ++++ .gitignore | 23 ++++++ LICENSE | 21 +++++ babel.config.js | 15 ++++ package.json | 57 +++++++++++++ postcss.config.js | 23 ++++++ public/favicon.ico | Bin 0 -> 4286 bytes public/index.html | 22 +++++ src/App.vue | 5 ++ src/api/user.js | 16 ++++ src/assets/logo.png | Bin 0 -> 17785 bytes src/components/BackTop/index.vue | 69 ++++++++++++++++ src/components/SvgIcon/index.vue | 53 ++++++++++++ src/icons/index.js | 9 ++ src/icons/svg/backtop.svg | 1 + src/icons/svg/qq.svg | 1 + src/icons/svg/search.svg | 1 + src/icons/svg/star.svg | 1 + src/icons/svg/user.svg | 1 + src/icons/svg/wechat.svg | 1 + src/icons/svgo.yml | 22 +++++ src/main.js | 42 ++++++++++ src/permission.js | 53 ++++++++++++ src/router/index.js | 29 +++++++ src/store/getters.js | 7 ++ src/store/index.js | 22 +++++ src/store/modules/user.js | 90 ++++++++++++++++++++ src/styles/reset.css | 129 +++++++++++++++++++++++++++++ src/utils/auth.js | 15 ++++ src/utils/request.js | 60 ++++++++++++++ src/views/about/iconfont.vue | 26 ++++++ src/views/auth/login.vue | 138 +++++++++++++++++++++++++++++++ src/views/home/index.vue | 69 ++++++++++++++++ vue.config.js | 103 +++++++++++++++++++++++ 39 files changed, 1173 insertions(+) create mode 100644 .browserslistrc create mode 100644 .editorconfig create mode 100644 .env.development create mode 100644 .env.production create mode 100644 .eslintignore create mode 100644 .eslintrc.js create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 babel.config.js create mode 100644 package.json create mode 100644 postcss.config.js create mode 100644 public/favicon.ico create mode 100644 public/index.html create mode 100644 src/App.vue create mode 100644 src/api/user.js create mode 100644 src/assets/logo.png create mode 100644 src/components/BackTop/index.vue create mode 100644 src/components/SvgIcon/index.vue create mode 100644 src/icons/index.js create mode 100644 src/icons/svg/backtop.svg create mode 100644 src/icons/svg/qq.svg create mode 100644 src/icons/svg/search.svg create mode 100644 src/icons/svg/star.svg create mode 100644 src/icons/svg/user.svg create mode 100644 src/icons/svg/wechat.svg create mode 100644 src/icons/svgo.yml create mode 100644 src/main.js create mode 100644 src/permission.js create mode 100644 src/router/index.js create mode 100644 src/store/getters.js create mode 100644 src/store/index.js create mode 100644 src/store/modules/user.js create mode 100644 src/styles/reset.css create mode 100644 src/utils/auth.js create mode 100644 src/utils/request.js create mode 100644 src/views/about/iconfont.vue create mode 100644 src/views/auth/login.vue create mode 100644 src/views/home/index.vue create mode 100644 vue.config.js diff --git a/.browserslistrc b/.browserslistrc new file mode 100644 index 0000000..d6471a3 --- /dev/null +++ b/.browserslistrc @@ -0,0 +1,2 @@ +> 1% +last 2 versions diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..7053c49 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,5 @@ +[*.{js,jsx,ts,tsx,vue}] +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/.env.development b/.env.development new file mode 100644 index 0000000..8f5856d --- /dev/null +++ b/.env.development @@ -0,0 +1,14 @@ +# just a flag +ENV = 'development' + +# base api +VUE_APP_BASE_API = '/dev-api' + +# vue-cli uses the VUE_CLI_BABEL_TRANSPILE_MODULES environment variable, +# to control whether the babel-plugin-dynamic-import-node plugin is enabled. +# It only does one thing by converting all import() to require(). +# This configuration can significantly increase the speed of hot updates, +# when you have a large number of pages. +# Detail: https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/babel-preset-app/index.js + +VUE_CLI_BABEL_TRANSPILE_MODULES = true diff --git a/.env.production b/.env.production new file mode 100644 index 0000000..80c8103 --- /dev/null +++ b/.env.production @@ -0,0 +1,6 @@ +# just a flag +ENV = 'production' + +# base api +VUE_APP_BASE_API = '/prod-api' + diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..e6529fc --- /dev/null +++ b/.eslintignore @@ -0,0 +1,4 @@ +build/*.js +src/assets +public +dist diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..c18ca28 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,18 @@ +module.exports = { + root: true, + env: { + node: true + }, + extends: [ + 'plugin:vue/essential', + '@vue/standard' + ], + parserOptions: { + parser: 'babel-eslint' + }, + rules: { + 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', + 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', + "space-before-function-paren": 0, + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..997c6eb --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +.DS_Store +node_modules +/dist +package-lock.json +yarn.lock + +# local env files +.env.local +.env.*.local + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..232db83 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Ewall&熊猫 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000..6c909a4 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,15 @@ +module.exports = { + presets: ['@vue/cli-plugin-babel/preset'], + // vant引入:https://youzan.github.io/vant/#/zh-CN/quickstart#yin-ru-zu-jian + plugins: [ + [ + 'import', + { + libraryName: 'vant', + libraryDirectory: 'es', + style: name => `${name}/style/less` + }, + 'vant' + ] + ] +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..d27b5e0 --- /dev/null +++ b/package.json @@ -0,0 +1,57 @@ +{ + "name": "panda-vue-template", + "version": "0.1.0", + "author": "Ewall&熊猫", + "license": "MIT", + "keywords": [ + "vue", + "vue-template", + "panda-vue-template" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/Ewall1106/panda-vue-template" + }, + "scripts": { + "serve": "vue-cli-service serve", + "build": "vue-cli-service build", + "lint": "vue-cli-service lint", + "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml" + }, + "dependencies": { + "axios": "^0.19.2", + "core-js": "^3.6.4", + "js-cookie": "^2.2.1", + "normalize.css": "^8.0.1", + "vant": "^2.5.5", + "vue": "^2.6.11", + "vue-router": "^3.1.5", + "vue-scrollto": "^2.17.1", + "vuex": "^3.1.2" + }, + "devDependencies": { + "@vue/cli-plugin-babel": "~4.2.0", + "@vue/cli-plugin-eslint": "~4.2.0", + "@vue/cli-plugin-router": "~4.2.0", + "@vue/cli-plugin-vuex": "~4.2.0", + "@vue/cli-service": "~4.2.0", + "@vue/eslint-config-standard": "^5.1.0", + "babel-eslint": "^10.0.3", + "babel-plugin-import": "^1.13.0", + "eslint": "^6.7.2", + "eslint-plugin-import": "^2.20.1", + "eslint-plugin-node": "^11.0.0", + "eslint-plugin-promise": "^4.2.1", + "eslint-plugin-standard": "^4.0.0", + "eslint-plugin-vue": "^6.1.2", + "less": "^3.11.1", + "less-loader": "^5.0.0", + "node-sass": "^4.13.1", + "postcss-preset-env": "^6.7.0", + "postcss-px-to-viewport": "^1.1.1", + "sass-loader": "^8.0.2", + "svg-sprite-loader": "^4.2.1", + "svgo": "^1.3.2", + "vue-template-compiler": "^2.6.11" + } +} diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..ed64934 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,23 @@ +module.exports = { + plugins: { + // https://github.com/csstools/postcss-preset-env + 'postcss-preset-env': {}, + // https://github.com/evrone/postcss-px-to-viewport/blob/master/README_CN.md + 'postcss-px-to-viewport': { + unitToConvert: 'px', + viewportWidth: 750, + unitPrecision: 3, + propList: ['*'], + viewportUnit: 'vw', + fontViewportUnit: 'vw', + selectorBlackList: ['.ignore', 'van'], + minPixelValue: 1, + mediaQuery: false, + replace: true, + exclude: [], + landscape: false, + landscapeUnit: 'vw', + landscapeWidth: 568 + } + } +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..df36fcfb72584e00488330b560ebcf34a41c64c2 GIT binary patch literal 4286 zcmds*O-Phc6o&64GDVCEQHxsW(p4>LW*W<827=Unuo8sGpRux(DN@jWP-e29Wl%wj zY84_aq9}^Am9-cWTD5GGEo#+5Fi2wX_P*bo+xO!)p*7B;iKlbFd(U~_d(U?#hLj56 zPhFkj-|A6~Qk#@g^#D^U0XT1cu=c-vu1+SElX9NR;kzAUV(q0|dl0|%h|dI$%VICy zJnu2^L*Te9JrJMGh%-P79CL0}dq92RGU6gI{v2~|)p}sG5x0U*z<8U;Ij*hB9z?ei z@g6Xq-pDoPl=MANPiR7%172VA%r)kevtV-_5H*QJKFmd;8yA$98zCxBZYXTNZ#QFk2(TX0;Y2dt&WitL#$96|gJY=3xX zpCoi|YNzgO3R`f@IiEeSmKrPSf#h#Qd<$%Ej^RIeeYfsxhPMOG`S`Pz8q``=511zm zAm)MX5AV^5xIWPyEu7u>qYs?pn$I4nL9J!=K=SGlKLXpE<5x+2cDTXq?brj?n6sp= zphe9;_JHf40^9~}9i08r{XM$7HB!`{Ys~TK0kx<}ZQng`UPvH*11|q7&l9?@FQz;8 zx!=3<4seY*%=OlbCbcae?5^V_}*K>Uo6ZWV8mTyE^B=DKy7-sdLYkR5Z?paTgK-zyIkKjIcpyO z{+uIt&YSa_$QnN_@t~L014dyK(fOOo+W*MIxbA6Ndgr=Y!f#Tokqv}n<7-9qfHkc3 z=>a|HWqcX8fzQCT=dqVbogRq!-S>H%yA{1w#2Pn;=e>JiEj7Hl;zdt-2f+j2%DeVD zsW0Ab)ZK@0cIW%W7z}H{&~yGhn~D;aiP4=;m-HCo`BEI+Kd6 z={Xwx{TKxD#iCLfl2vQGDitKtN>z|-AdCN|$jTFDg0m3O`WLD4_s#$S literal 0 HcmV?d00001 diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..bb172ba --- /dev/null +++ b/public/index.html @@ -0,0 +1,22 @@ + + + + + + + + + <%= htmlWebpackPlugin.options.title %> + + + + +
+ + + + \ No newline at end of file diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 0000000..d3e2cd8 --- /dev/null +++ b/src/App.vue @@ -0,0 +1,5 @@ + diff --git a/src/api/user.js b/src/api/user.js new file mode 100644 index 0000000..d155005 --- /dev/null +++ b/src/api/user.js @@ -0,0 +1,16 @@ +import request from '@/utils/request' + +export function getInfo() { + return request({ + url: '/user/info', + method: 'get' + }) +} + +export function login(data) { + return request({ + url: '/user/login', + method: 'post', + data + }) +} diff --git a/src/assets/logo.png b/src/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..89ffdd0a5177e24dd9be9e4bc7078fc890bd9680 GIT binary patch literal 17785 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 +
+ + + +
+ + + + + diff --git a/src/components/SvgIcon/index.vue b/src/components/SvgIcon/index.vue new file mode 100644 index 0000000..a4f0252 --- /dev/null +++ b/src/components/SvgIcon/index.vue @@ -0,0 +1,53 @@ + + + + + diff --git a/src/icons/index.js b/src/icons/index.js new file mode 100644 index 0000000..28ae463 --- /dev/null +++ b/src/icons/index.js @@ -0,0 +1,9 @@ +import Vue from 'vue' +import SvgIcon from '@/components/SvgIcon' + +// register globally +Vue.component('svg-icon', SvgIcon) + +const req = require.context('./svg', false, /\.svg$/) +const requireAll = requireContext => requireContext.keys().map(requireContext) +requireAll(req) diff --git a/src/icons/svg/backtop.svg b/src/icons/svg/backtop.svg new file mode 100644 index 0000000..f142331 --- /dev/null +++ b/src/icons/svg/backtop.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/qq.svg b/src/icons/svg/qq.svg new file mode 100644 index 0000000..ee13d4e --- /dev/null +++ b/src/icons/svg/qq.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/search.svg b/src/icons/svg/search.svg new file mode 100644 index 0000000..3110f2a --- /dev/null +++ b/src/icons/svg/search.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/star.svg b/src/icons/svg/star.svg new file mode 100644 index 0000000..63a68b3 --- /dev/null +++ b/src/icons/svg/star.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/user.svg b/src/icons/svg/user.svg new file mode 100644 index 0000000..0ba0716 --- /dev/null +++ b/src/icons/svg/user.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/wechat.svg b/src/icons/svg/wechat.svg new file mode 100644 index 0000000..c586e55 --- /dev/null +++ b/src/icons/svg/wechat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svgo.yml b/src/icons/svgo.yml new file mode 100644 index 0000000..d11906a --- /dev/null +++ b/src/icons/svgo.yml @@ -0,0 +1,22 @@ +# replace default config + +# multipass: true +# full: true + +plugins: + + # - name + # + # or: + # - name: false + # - name: true + # + # or: + # - name: + # param1: 1 + # param2: 2 + +- removeAttrs: + attrs: + - 'fill' + - 'fill-rule' diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..a9ef71e --- /dev/null +++ b/src/main.js @@ -0,0 +1,42 @@ +import Vue from 'vue' +// A modern alternative to CSS resets +import './styles/reset.css' +// https://github.com/necolas/normalize.css +import 'normalize.css/normalize.css' + +import App from './App.vue' +import router from './router' +import store from './store' + +import './icons' +import './permission' + +// vant +import { + Button, + Toast, + Dialog, + Field, + Form, + Notify, + Cell, + CellGroup, + NavBar +} from 'vant' +Vue.use(Toast) + .use(Dialog) + .use(Notify) + .use(Field) + .use(Form) + .use(Button) + .use(Cell) + .use(CellGroup) + .use(NavBar) + +Vue.config.productionTip = false + +new Vue({ + router, + store, + render: h => h(App) +}).$mount('#app') diff --git a/src/permission.js b/src/permission.js new file mode 100644 index 0000000..57f6d3d --- /dev/null +++ b/src/permission.js @@ -0,0 +1,53 @@ +import router from './router' +import store from './store' +import { Toast } from 'vant' +import { getToken } from '@/utils/auth' // get token from cookie + +const whiteList = ['/login'] // 白名单 + +router.beforeEach(async (to, from, next) => { + // 设置标题 + document.title = '熊猫商城' + + // 根据token判断用户是否登录 + const hasToken = getToken() + + console.log('adsfa', hasToken) + + if (hasToken) { + if (to.path === '/login') { + // 如果已经登录了,而去的又是login页就重定向到首页 + next({ path: '/' }) + } else { + const hasUserInfo = store.getters.name + console.log('asdfas', hasUserInfo) + if (hasUserInfo) { + next() + } else { + // 如果用户刷新了浏览器,那么需要重新请求基本信息塞到vuex中进行状态管理 + try { + await store.dispatch('user/getInfo') + next() + } catch (error) { + if (whiteList.indexOf(to.path) !== -1) { + next() + } else { + // 清空token重新去登录 + await store.dispatch('user/resetToken') + Toast.fail('出错了') + next(`/login?redirect=${encodeURIComponent(location.href)}`) + } + } + } + } + } else { + if (whiteList.indexOf(to.path) !== -1) { + // 白名单没有token也直接放行 + next() + } else { + // 反之则去登录页面 + next(`/login?redirect=${encodeURIComponent(location.href)}`) + // NProgress.done() + } + } +}) diff --git a/src/router/index.js b/src/router/index.js new file mode 100644 index 0000000..86dab02 --- /dev/null +++ b/src/router/index.js @@ -0,0 +1,29 @@ +import Vue from 'vue' +import VueRouter from 'vue-router' + +Vue.use(VueRouter) + +const routes = [ + { + path: '*', + name: 'Home', + component: () => import('@/views/home') + }, + { + path: '/login', + name: 'Login', + component: () => import('@/views/auth/login') + }, + { + path: '/iconfont', + name: 'IconFont', + component: () => import('@/views/about/iconfont') + } +] + +const router = new VueRouter({ + scrollBehavior: () => ({ y: 0 }), + routes +}) + +export default router diff --git a/src/store/getters.js b/src/store/getters.js new file mode 100644 index 0000000..1d8bf04 --- /dev/null +++ b/src/store/getters.js @@ -0,0 +1,7 @@ +const getters = { + avatar: state => state.user.avatar, + name: state => state.user.name, + token: state => state.user.token +} + +export default getters diff --git a/src/store/index.js b/src/store/index.js new file mode 100644 index 0000000..d12f06b --- /dev/null +++ b/src/store/index.js @@ -0,0 +1,22 @@ +import Vue from 'vue' +import Vuex from 'vuex' +import getters from './getters' + +Vue.use(Vuex) + +// https://webpack.js.org/guides/dependency-management/#requirecontext +const modulesFiles = require.context('./modules', true, /\.js$/) + +const modules = modulesFiles.keys().reduce((modules, modulePath) => { + const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1') + const value = modulesFiles(modulePath) + modules[moduleName] = value.default + return modules +}, {}) + +const store = new Vuex.Store({ + modules, + getters +}) + +export default store diff --git a/src/store/modules/user.js b/src/store/modules/user.js new file mode 100644 index 0000000..20b9456 --- /dev/null +++ b/src/store/modules/user.js @@ -0,0 +1,90 @@ +import { login, logout, getInfo } from '@/api/user' +import { getToken, setToken, removeToken } from '@/utils/auth' + +const state = { + token: getToken(), + name: '', + avatar: '' +} + +const mutations = { + SET_TOKEN: (state, token) => { + state.token = token + }, + SET_NAME: (state, name) => { + state.name = name + }, + SET_AVATAR: (state, avatar) => { + state.avatar = avatar + } +} + +const actions = { + // 登录 + login({ commit }, userInfo) { + const { phonenum, password } = userInfo + return new Promise((resolve, reject) => { + login({ phonenum, password }) + .then(res => { + const { token } = res.entry + commit('SET_TOKEN', token) + setToken(token) + resolve() + }) + .catch(error => { + reject(error) + }) + }) + }, + + // 登出 + logout({ commit, state }) { + return new Promise((resolve, reject) => { + logout(state.token) + .then(() => { + commit('SET_TOKEN', '') + removeToken() + + resolve() + }) + .catch(error => { + reject(error) + }) + }) + }, + + // 获取基本用户信息 + getInfo({ commit, state }) { + return new Promise((resolve, reject) => { + getInfo(state.token) + .then(res => { + const data = res.entry + if (!data) { + reject(new Error('获取基本信息失败,请重新登录')) + } + commit('SET_NAME', data.name) + commit('SET_AVATAR', data.avatar) + resolve(data) + }) + .catch(error => { + reject(error) + }) + }) + }, + + // 重置token + resetToken({ commit }) { + return new Promise(resolve => { + commit('SET_TOKEN', '') + removeToken() + resolve() + }) + } +} + +export default { + namespaced: true, + state, + mutations, + actions +} diff --git a/src/styles/reset.css b/src/styles/reset.css new file mode 100644 index 0000000..45a05ec --- /dev/null +++ b/src/styles/reset.css @@ -0,0 +1,129 @@ +/* http://meyerweb.com/eric/tools/css/reset/ + v2.0 | 20110126 + License: none (public domain) +*/ + +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, +hgroup, +menu, +nav, +output, +ruby, +section, +summary, +time, +mark, +audio, +video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +menu, +nav, +section { + display: block; +} +body { + line-height: 1; +} +ol, +ul { + list-style: none; +} +blockquote, +q { + quotes: none; +} +blockquote:before, +blockquote:after, +q:before, +q:after { + content: ""; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} diff --git a/src/utils/auth.js b/src/utils/auth.js new file mode 100644 index 0000000..b04f3de --- /dev/null +++ b/src/utils/auth.js @@ -0,0 +1,15 @@ +import Cookies from 'js-cookie' + +const key = 'MallToken' + +export function getToken() { + return Cookies.get(key) +} + +export function setToken(token) { + return Cookies.set(key, token) +} + +export function removeToken() { + return Cookies.remove(key) +} diff --git a/src/utils/request.js b/src/utils/request.js new file mode 100644 index 0000000..4ea801e --- /dev/null +++ b/src/utils/request.js @@ -0,0 +1,60 @@ +import axios from 'axios' +import { Toast, Dialog } from 'vant' +import store from '@/store' +import { getToken } from '@/utils/auth' + +// 创建一个axios实例 +const service = axios.create({ + baseURL: process.env.VUE_APP_BASE_API, + // withCredentials: true, + timeout: 5000 +}) + +// 请求拦截器 +service.interceptors.request.use( + config => { + if (store.getters.token) { + // ['X-Token']是我这里自定义测试而塞到请求头中 + config.headers['X-TOKEN'] = getToken() + } + return config + }, + error => { + console.log(error) + return Promise.reject(error) + } +) + +// 响应拦截器 +service.interceptors.response.use( + response => { + const res = response.data + + // 与后端约定的错误码 + if (res.code !== 200) { + Toast.fail(res.message) + // 现约定 50001:无效token 50002:token过期 + if (res.code === 50001 || res.code === 50002) { + Dialog.alert({ + title: '提示', + message: '您还未登录或登录已过期,请重新登录' + }).then(() => { + store.dispatch('user/resetToken').then(() => { + location.reload() + }) + }) + } + + return Promise.reject(new Error(res.message || 'Error')) + } else { + return res + } + }, + error => { + console.log('err' + error) + Toast.fail(error.message) + return Promise.reject(error) + } +) + +export default service diff --git a/src/views/about/iconfont.vue b/src/views/about/iconfont.vue new file mode 100644 index 0000000..61f45c7 --- /dev/null +++ b/src/views/about/iconfont.vue @@ -0,0 +1,26 @@ + + + diff --git a/src/views/auth/login.vue b/src/views/auth/login.vue new file mode 100644 index 0000000..f9bf375 --- /dev/null +++ b/src/views/auth/login.vue @@ -0,0 +1,138 @@ + + + + + diff --git a/src/views/home/index.vue b/src/views/home/index.vue new file mode 100644 index 0000000..15c67a6 --- /dev/null +++ b/src/views/home/index.vue @@ -0,0 +1,69 @@ + + + + + diff --git a/vue.config.js b/vue.config.js new file mode 100644 index 0000000..3f8e120 --- /dev/null +++ b/vue.config.js @@ -0,0 +1,103 @@ +'use strict' +const path = require('path') + +const mockUrl = 'http://yapi.demo.qunar.com/mock/17982' + +function resolve (dir) { + return path.join(__dirname, dir) +} + +// All configuration item explanations can be find in https://cli.vuejs.org/config/ +module.exports = { + publicPath: '/', + outputDir: 'dist', + assetsDir: 'static', + lintOnSave: process.env.NODE_ENV === 'development', + productionSourceMap: false, + devServer: { + port: 8080, + open: true, + overlay: { + warnings: false, + errors: true + }, + proxy: { + '/dev-api': { + target: mockUrl, + pathRewrite: { '^/dev-api': '' }, + secure: false, + changeOrigin: true + } + } + }, + configureWebpack: { + // provide the app's title in webpack's name field, so that + // it can be accessed in index.html to inject the correct title. + name: 'panda vue template', + resolve: { + alias: { + '@': resolve('src') + } + } + }, + chainWebpack (config) { + config.plugins.delete('preload') // TODO: need test + config.plugins.delete('prefetch') // TODO: need test + + // set svg-sprite-loader + config.module + .rule('svg') + .exclude.add(resolve('src/icons')) + .end() + config.module + .rule('icons') + .test(/\.svg$/) + .include.add(resolve('src/icons')) + .end() + .use('svg-sprite-loader') + .loader('svg-sprite-loader') + .options({ + symbolId: 'icon-[name]' + }) + .end() + + // set preserveWhitespace + config.module + .rule('vue') + .use('vue-loader') + .loader('vue-loader') + .tap(options => { + options.compilerOptions.preserveWhitespace = true + return options + }) + .end() + + config + // https://webpack.js.org/configuration/devtool/#development + .when(process.env.NODE_ENV === 'development', config => + config.devtool('cheap-source-map') + ) + + config.when(process.env.NODE_ENV !== 'development', config => { + config.optimization.splitChunks({ + chunks: 'all', + cacheGroups: { + libs: { + name: 'chunk-libs', + test: /[\\/]node_modules[\\/]/, + priority: 10, + chunks: 'initial' // only package third parties that are initially dependent + }, + commons: { + name: 'chunk-commons', + test: resolve('src/components'), // can customize your rules + minChunks: 3, // minimum common number + priority: 5, + reuseExistingChunk: true + } + } + }) + config.optimization.runtimeChunk('single') + }) + } +}