Merge Request #4
← To merge requests
From
adam:master
into
jp:master
Commits (1)
Showing
7 changed files
Show diff stats
mock/mock-server.js
| 1 | const chokidar = require('chokidar') | 1 | const chokidar = require('chokidar') |
| 2 | const bodyParser = require('body-parser') | 2 | const bodyParser = require('body-parser') |
| 3 | const chalk = require('chalk') | 3 | const chalk = require('chalk') |
| 4 | const path = require('path') | 4 | const path = require('path') |
| 5 | 5 | ||
| 6 | const mockDir = path.join(process.cwd(), 'mock') | 6 | const mockDir = path.join(process.cwd(), 'mock') |
| 7 | 7 | ||
| 8 | function registerRoutes(app) { | 8 | function registerRoutes(app) { |
| 9 | let mockLastIndex | 9 | let mockLastIndex |
| 10 | const { default: mocks } = require('./index.js') | 10 | const { default: mocks } = require('./index.js') |
| 11 | for (const mock of mocks) { | 11 | for (const mock of mocks) { |
| 12 | app[mock.type](mock.url, mock.response) | 12 | app[mock.type](mock.url, mock.response) |
| 13 | mockLastIndex = app._router.stack.length | 13 | mockLastIndex = app._router.stack.length |
| 14 | } | 14 | } |
| 15 | const mockRoutesLength = Object.keys(mocks).length | 15 | const mockRoutesLength = Object.keys(mocks).length |
| 16 | return { | 16 | return { |
| 17 | mockRoutesLength: mockRoutesLength, | 17 | mockRoutesLength: mockRoutesLength, |
| 18 | mockStartIndex: mockLastIndex - mockRoutesLength | 18 | mockStartIndex: mockLastIndex - mockRoutesLength |
| 19 | } | 19 | } |
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | function unregisterRoutes() { | 22 | function unregisterRoutes() { |
| 23 | Object.keys(require.cache).forEach(i => { | 23 | Object.keys(require.cache).forEach(i => { |
| 24 | if (i.includes(mockDir)) { | 24 | if (i.includes(mockDir)) { |
| 25 | delete require.cache[require.resolve(i)] | 25 | delete require.cache[require.resolve(i)] |
| 26 | } | 26 | } |
| 27 | }) | 27 | }) |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | module.exports = app => { | 30 | module.exports = app => { |
| 31 | // es6 polyfill | 31 | // es6 polyfill |
| 32 | require('@babel/register') | 32 | require('@babel/register') |
| 33 | 33 | ||
| 34 | // parse app.body | 34 | // parse app.body |
| 35 | // https://expressjs.com/en/4x/api.html#req.body | 35 | // https://expressjs.com/en/4x/api.html#req.body |
| 36 | app.use(bodyParser.json()) | 36 | app.use(bodyParser.json()) |
| 37 | app.use(bodyParser.urlencoded({ | 37 | app.use(bodyParser.urlencoded({ |
| 38 | extended: true | 38 | extended: true |
| 39 | })) | 39 | })) |
| 40 | 40 | ||
| 41 | const mockRoutes = registerRoutes(app) | 41 | const mockRoutes = registerRoutes(app) |
| 42 | var mockRoutesLength = mockRoutes.mockRoutesLength | 42 | var mockRoutesLength = mockRoutes.mockRoutesLength |
| 43 | var mockStartIndex = mockRoutes.mockStartIndex | 43 | var mockStartIndex = mockRoutes.mockStartIndex |
| 44 | 44 | ||
| 45 | // watch files, hot reload mock server | 45 | // watch files, hot reload mock server |
| 46 | chokidar.watch(mockDir, { | 46 | chokidar.watch(mockDir, { |
| 47 | ignored: /mock-server/, | 47 | ignored: /mock-server/, |
| 48 | ignoreInitial: true | 48 | ignoreInitial: true |
| 49 | }).on('all', (event, path) => { | 49 | }).on('all', (event, path) => { |
| 50 | if (event === 'change' || event === 'add') { | 50 | if (event === 'change' || event === 'add') { |
| 51 | try { | 51 | try { |
| 52 | // remove mock routes stack | 52 | // remove mock routes stack |
| 53 | app._router.stack.splice(mockStartIndex, mockRoutesLength) | 53 | app._router.stack.splice(mockStartIndex, mockRoutesLength) |
| 54 | 54 | ||
| 55 | // clear routes cache | 55 | // clear routes cache |
| 56 | unregisterRoutes() | 56 | unregisterRoutes() |
| 57 | 57 | ||
| 58 | const mockRoutes = registerRoutes(app) | 58 | const mockRoutes = registerRoutes(app) |
| 59 | mockRoutesLength = mockRoutes.mockRoutesLength | 59 | mockRoutesLength = mockRoutes.mockRoutesLength |
| 60 | mockStartIndex = mockRoutes.mockStartIndex | 60 | mockStartIndex = mockRoutes.mockStartIndex |
| 61 | 61 | ||
| 62 | console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed ${path}`)) | 62 | console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed ${path}`)) |
| 63 | } catch (error) { | 63 | } catch (error) { |
| 64 | console.log(chalk.redBright(error)) | 64 | console.error(chalk.redBright(error)) |
| 65 | } | 65 | } |
| 66 | } | 66 | } |
| 67 | }) | 67 | }) |
| 68 | } | 68 | } |
| 69 | 69 |
mock/user.js
| 1 | |||
| 2 | const tokens = { | 1 | const tokens = { |
| 3 | admin: { | 2 | admin: { |
| 4 | token: 'admin-token' | 3 | token: 'admin-token' |
| 5 | }, | 4 | }, |
| 6 | assistant: { | 5 | assistant: { |
| 7 | token: 'assistant-token' | 6 | token: 'assistant-token' |
| 8 | }, | 7 | }, |
| 9 | editor: { | 8 | runner: { |
| 10 | token: 'editor-token' | 9 | token: 'runner-token' |
| 11 | }, | 10 | }, |
| 12 | shoper: { | 11 | shoper: { |
| 13 | token: 'shoper-token' | 12 | token: 'shoper-token' |
| 14 | } | 13 | } |
| 15 | } | 14 | } |
| 16 | 15 | ||
| 17 | const users = { | 16 | const users = { |
| 18 | 'admin-token': {//管理员 | 17 | 'admin-token': { //管理员 |
| 19 | roles: ['admin'], | 18 | roles: ['admin'], |
| 20 | introduction: 'I am a super administrator', | 19 | introduction: 'I am a super administrator', |
| 21 | avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', | 20 | avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', |
| 22 | name: 'Super Admin' | 21 | name: 'Super Admin' |
| 23 | }, | 22 | }, |
| 24 | 'assistant-token': {//管理员助理 | 23 | 'assistant-token': { //管理员助理 |
| 25 | roles: ['assistant'], | 24 | roles: ['assistant'], |
| 26 | introduction: 'I am a assistant of administrator', | 25 | introduction: 'I am a assistant of administrator', |
| 27 | avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', | 26 | avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', |
| 28 | name: 'Super Admin' | 27 | name: 'assistant Admin' |
| 29 | }, | 28 | }, |
| 30 | 'editor-token': {//运营人员 | 29 | 'runner-token': { //运营人员 |
| 31 | roles: ['editor'], | 30 | roles: ['runner'], |
| 32 | introduction: 'I am an editor', | 31 | introduction: 'I am an runner', |
| 33 | avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', | 32 | avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', |
| 34 | name: 'Normal Editor' | 33 | name: 'Normal runner' |
| 35 | }, | 34 | }, |
| 36 | 'shoper-token': {//供应商 | 35 | 'shoper-token': { //供应商 |
| 37 | roles: ['shoper'], | 36 | roles: ['shoper'], |
| 38 | introduction: 'I am an shoper', | 37 | introduction: 'I am an shoper', |
| 39 | avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', | 38 | avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', |
| 40 | name: 'Normal Editor' | 39 | name: 'Normal shoper' |
| 41 | } | 40 | } |
| 42 | } | 41 | } |
| 43 | 42 | ||
| 44 | export default [ | 43 | export default [{ // user login |
| 45 | // user login | ||
| 46 | { | ||
| 47 | url: '/yp/user/login', | 44 | url: '/yp/user/login', |
| 48 | type: 'post', | 45 | type: 'post', |
| 49 | response: config => { | 46 | response: config => { |
| 50 | const { username } = config.body | 47 | console.log('config-------->', config.body); |
| 51 | const token = tokens[username] | 48 | const { |
| 52 | // mock error | 49 | username, |
| 53 | if (!token) { | 50 | password |
| 51 | } = config.body; | ||
| 52 | if (username == 'admin' && password == '111111') { | ||
| 53 | const token = tokens[username]; | ||
| 54 | if (!token) { | ||
| 55 | return { | ||
| 56 | code: 60204, | ||
| 57 | message: 'Account and password are incorrect.' | ||
| 58 | } | ||
| 59 | } else { | ||
| 60 | return { | ||
| 61 | code: 20000, | ||
| 62 | data: token | ||
| 63 | } | ||
| 64 | } | ||
| 65 | } else { | ||
| 54 | return { | 66 | return { |
| 55 | code: 60204, | 67 | code: 60204, |
| 56 | message: 'Account and password are incorrect.' | 68 | message: 'Account and password are incorrect.' |
| 57 | } | 69 | } |
| 58 | } | 70 | } |
| 59 | |||
| 60 | return { | ||
| 61 | code: 20000, | ||
| 62 | data: token | ||
| 63 | } | ||
| 64 | } | 71 | } |
| 65 | }, | 72 | }, |
| 66 | 73 | ||
| 67 | // get user info | 74 | // get user info |
| 68 | { | 75 | { |
| 69 | url: '/yp/user/info\.*', | 76 | url: '/yp/user/info\.*', |
| 70 | type: 'get', | 77 | type: 'get', |
| 71 | response: config => { | 78 | response: config => { |
| 72 | const { token } = config.query | 79 | const { |
| 80 | token | ||
| 81 | } = config.query | ||
| 73 | const info = users[token] | 82 | const info = users[token] |
| 74 | 83 | ||
| 75 | // mock error | 84 | // mock error |
| 76 | if (!info) { | 85 | if (!info) { |
| 77 | return { | 86 | return { |
| 78 | code: 50008, | 87 | code: 50008, |
| 79 | message: 'Login failed, unable to get user details.' | 88 | message: 'Login failed, unable to get user details.' |
| 80 | } | 89 | } |
| 81 | } | 90 | } |
| 82 | 91 | ||
| 83 | return { | 92 | return { |
| 84 | code: 20000, | 93 | code: 20000, |
| 85 | data: info | 94 | data: info |
| 86 | } | 95 | } |
| 87 | } | 96 | } |
| 88 | }, | 97 | }, |
| 89 | 98 | ||
| 90 | // user logout | 99 | // user logout |
| 91 | { | 100 | { |
| 92 | url: '/yp/user/logout', | 101 | url: '/yp/user/logout', |
| 93 | type: 'post', | 102 | type: 'post', |
| 94 | response: _ => { | 103 | response: _ => { |
src/api/user.js
| 1 | import request from '@/utils/request' | 1 | import request from '@/utils/request' |
| 2 | // var qs = require('Qs'); | ||
| 2 | 3 | ||
| 3 | export function login(data) { | 4 | export function login(data) { |
| 4 | console.log('login....', data) | 5 | console.log('login.1111...', data) |
| 5 | return request({ | 6 | return request({ |
| 6 | url: '/yp/user/login', | 7 | // url: '/yp/user/login', |
| 8 | url: '/yp.user.login.php', | ||
| 7 | method: 'post', | 9 | method: 'post', |
| 8 | data | 10 | headers: { |
| 9 | }) | 11 | 'Content-type': 'application/x-www-form-urlencoded' |
| 12 | }, | ||
| 13 | data, | ||
| 14 | // responseType: 'text/plain', | ||
| 15 | // onDownloadProgress: false, | ||
| 16 | // onUploadProgress: true, | ||
| 17 | // proxy: {} | ||
| 18 | }); | ||
| 10 | } | 19 | } |
| 11 | 20 | ||
| 12 | export function getInfo(token) { | 21 | export function getInfo(token) { |
| 13 | console.log('getInfo....', token) | 22 | console.log('getInfo....', token) |
| 14 | return request({ | 23 | return request({ |
| 15 | url: '/yp/user/info', | 24 | url: '/yp/user/info', |
| 16 | method: 'get', | 25 | method: 'get', |
| 17 | params: { token } | 26 | params: { |
| 27 | token | ||
| 28 | } | ||
| 18 | }) | 29 | }) |
| 19 | } | 30 | } |
| 20 | 31 | ||
| 21 | export function list(token) { | 32 | export function list(token) { |
| 22 | console.log('listUser....', token) | 33 | console.log('listUser....', token) |
| 23 | return request({ | 34 | return request({ |
| 24 | url: '/yp/user/list', | 35 | url: '/yp/user/list', |
| 25 | method: 'get', | 36 | method: 'get', |
| 26 | params: { token } | 37 | params: { |
| 38 | token | ||
| 39 | } | ||
| 27 | }) | 40 | }) |
| 28 | } | 41 | } |
| 29 | 42 | ||
| 30 | export function add(token) { | 43 | export function add(token) { |
| 31 | console.log('addUser....', token) | 44 | console.log('addUser....', token) |
| 32 | return request({ | 45 | return request({ |
| 33 | url: '/yp/user/add', | 46 | url: '/yp/user/add', |
| 34 | method: 'get', | 47 | method: 'get', |
| 35 | params: { token } | 48 | params: { |
| 49 | token | ||
| 50 | } | ||
| 36 | }) | 51 | }) |
| 37 | } | 52 | } |
| 38 | 53 | ||
| 39 | export function modi(token) { | 54 | export function modi(token) { |
| 40 | console.log('modiUser....', token) | 55 | console.log('modiUser....', token) |
| 41 | return request({ | 56 | return request({ |
| 42 | url: '/yp/user/modi', | 57 | url: '/yp/user/modi', |
| 43 | method: 'get', | 58 | method: 'get', |
| 44 | params: { token } | 59 | params: { |
| 60 | token | ||
| 61 | } | ||
| 45 | }) | 62 | }) |
| 46 | } | 63 | } |
| 47 | 64 | ||
| 48 | export function logout() { | 65 | export function logout() { |
| 49 | console.log('logout....') | 66 | console.log('logout....') |
| 50 | return request({ | 67 | return request({ |
| 51 | url: '/yp/user/logout', | 68 | url: '/yp/user/logout', |
| 52 | method: 'post' | 69 | method: 'post' |
| 53 | }) | 70 | }) |
| 54 | } | 71 | } |
| 55 | 72 |
src/store/modules/user.js
| 1 | import { login, logout, getInfo } from '@/api/user' | 1 | import { login, logout, getInfo } from '@/api/user' |
| 2 | import { getToken, setToken, removeToken } from '@/utils/auth' | 2 | import { getToken, setToken, removeToken } from '@/utils/auth' |
| 3 | import { resetRouter } from '@/router' | 3 | import { resetRouter } from '@/router' |
| 4 | 4 | ||
| 5 | const getDefaultState = () => { | 5 | const getDefaultState = () => { |
| 6 | return { | 6 | return { |
| 7 | token: getToken(), | 7 | token: getToken(), |
| 8 | name: '', | 8 | name: '', |
| 9 | avatar: '', | 9 | avatar: '', |
| 10 | roles: [] | 10 | roles: [] |
| 11 | } | 11 | } |
| 12 | } | 12 | } |
| 13 | 13 | ||
| 14 | const state = getDefaultState() | 14 | const state = getDefaultState() |
| 15 | 15 | ||
| 16 | const mutations = { | 16 | const mutations = { |
| 17 | RESET_STATE: (state) => { | 17 | RESET_STATE: (state) => { |
| 18 | Object.assign(state, getDefaultState()) | 18 | Object.assign(state, getDefaultState()) |
| 19 | }, | 19 | }, |
| 20 | SET_TOKEN: (state, token) => { | 20 | SET_TOKEN: (state, token) => { |
| 21 | state.token = token | 21 | state.token = token |
| 22 | }, | 22 | }, |
| 23 | SET_NAME: (state, name) => { | 23 | SET_NAME: (state, name) => { |
| 24 | state.name = name | 24 | state.name = name |
| 25 | }, | 25 | }, |
| 26 | SET_AVATAR: (state, avatar) => { | 26 | SET_AVATAR: (state, avatar) => { |
| 27 | state.avatar = avatar | 27 | state.avatar = avatar |
| 28 | }, | 28 | }, |
| 29 | SET_ROLES: (state, roles) => { | 29 | SET_ROLES: (state, roles) => { |
| 30 | state.roles = roles | 30 | state.roles = roles |
| 31 | } | 31 | } |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | const actions = { | 34 | const actions = { |
| 35 | // user login | 35 | // user login |
| 36 | login({ commit }, userInfo) { | 36 | login({ commit }, userInfo) { |
| 37 | const { username, password } = userInfo | 37 | const { username, password } = userInfo |
| 38 | return new Promise((resolve, reject) => { | 38 | return new Promise((resolve, reject) => { |
| 39 | login({ username: username.trim(), password: password }).then(response => { | 39 | login({ username: username.trim(), password: password }).then(response => { |
| 40 | const { data } = response | 40 | const { data } = response |
| 41 | console.log('action------->login------->处理', data); | ||
| 41 | commit('SET_TOKEN', data.token) | 42 | commit('SET_TOKEN', data.token) |
| 42 | setToken(data.token) | 43 | setToken(data.token) |
| 43 | resolve() | 44 | resolve() |
| 44 | }).catch(error => { | 45 | }).catch(error => { |
| 45 | reject(error) | 46 | reject(error) |
| 46 | }) | 47 | }) |
| 47 | }) | 48 | }) |
| 48 | }, | 49 | }, |
| 49 | 50 | ||
| 50 | // get user info | 51 | // get user info |
| 51 | getInfo({ commit, state }) { | 52 | getInfo({ commit, state }) { |
| 52 | return new Promise((resolve, reject) => { | 53 | return new Promise((resolve, reject) => { |
| 53 | getInfo(state.token).then(response => { | 54 | getInfo(state.token).then(response => { |
| 54 | const { data } = response | 55 | const { data } = response |
| 55 | |||
| 56 | if (!data) { | 56 | if (!data) { |
| 57 | reject('Verification failed, please Login again.') | 57 | reject('Verification failed, please Login again.') |
| 58 | } | 58 | } |
| 59 | |||
| 60 | const { roles, name, avatar } = data | 59 | const { roles, name, avatar } = data |
| 61 | |||
| 62 | // roles must be a non-empty array | 60 | // roles must be a non-empty array |
| 63 | if (!roles || roles.length <= 0) { | 61 | if (!roles || roles.length <= 0) { |
| 64 | reject('getInfo: roles must be a non-null array!') | 62 | reject('getInfo: roles must be a non-null array!') |
| 65 | } | 63 | } |
| 66 | |||
| 67 | commit('SET_ROLES', roles) | 64 | commit('SET_ROLES', roles) |
| 68 | commit('SET_NAME', name) | 65 | commit('SET_NAME', name) |
| 69 | commit('SET_AVATAR', avatar) | 66 | commit('SET_AVATAR', avatar) |
| 70 | resolve(data) | 67 | resolve(data) |
| 71 | }).catch(error => { | 68 | }).catch(error => { |
| 72 | reject(error) | 69 | reject(error) |
| 73 | }) | 70 | }) |
| 74 | }) | 71 | }) |
| 75 | }, | 72 | }, |
| 76 | 73 | ||
| 77 | // user logout | 74 | // user logout |
| 78 | logout({ commit, state }) { | 75 | logout({ commit, state }) { |
| 79 | return new Promise((resolve, reject) => { | 76 | return new Promise((resolve, reject) => { |
| 80 | logout(state.token).then(() => { | 77 | logout(state.token).then(() => { |
| 81 | removeToken() // must remove token first | 78 | removeToken() // must remove token first |
| 82 | resetRouter() | 79 | resetRouter() |
| 83 | commit('RESET_STATE') | 80 | commit('RESET_STATE') |
| 84 | resolve() | 81 | resolve() |
| 85 | }).catch(error => { | 82 | }).catch(error => { |
| 86 | reject(error) | 83 | reject(error) |
| 87 | }) | 84 | }) |
| 88 | }) | 85 | }) |
| 89 | }, | 86 | }, |
| 90 | 87 | ||
| 91 | // remove token | 88 | // remove token |
| 92 | resetToken({ commit }) { | 89 | resetToken({ commit }) { |
| 93 | return new Promise(resolve => { | 90 | return new Promise(resolve => { |
| 94 | removeToken() // must remove token first | 91 | removeToken() // must remove token first |
| 95 | commit('RESET_STATE') | 92 | commit('RESET_STATE') |
| 96 | resolve() | 93 | resolve() |
| 97 | }) | 94 | }) |
| 98 | } | 95 | } |
| 99 | } | 96 | } |
| 100 | 97 | ||
| 101 | export default { | 98 | export default { |
| 102 | namespaced: true, | 99 | namespaced: true, |
| 103 | state, | 100 | state, |
| 104 | mutations, | 101 | mutations, |
| 105 | actions | 102 | actions |
| 106 | } | 103 | } |
| 107 | 104 |
src/utils/request.js
| 1 | import axios from 'axios' | 1 | import axios from 'axios' |
| 2 | import { MessageBox, Message } from 'element-ui' | 2 | import { |
| 3 | MessageBox, | ||
| 4 | Message | ||
| 5 | } from 'element-ui' | ||
| 3 | import store from '@/store' | 6 | import store from '@/store' |
| 4 | import { getToken } from '@/utils/auth' | 7 | import { |
| 8 | getToken | ||
| 9 | } from '@/utils/auth' | ||
| 5 | 10 | ||
| 6 | // create an axios instance | 11 | // create an axios instance |
| 7 | // 创建axios实例 | 12 | // 创建axios实例 |
| 8 | const service = axios.create({ | 13 | const service = axios.create({ |
| 14 | // baseURL: '', // url = base url + request url | ||
| 9 | baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url | 15 | baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url |
| 10 | // withCredentials: true, // send cookies when cross-domain requests | 16 | // withCredentials: true, // send cookies when cross-domain requests |
| 11 | timeout: 5000 // request timeout | 17 | timeout: 5000, // request timeout |
| 18 | headers: { | ||
| 19 | 'Content-Type': 'application/x-www-form-urlencoded' | ||
| 20 | } | ||
| 12 | }) | 21 | }) |
| 13 | 22 | ||
| 14 | // request interceptor | 23 | // request interceptor |
| 15 | // request拦截器 | 24 | // request拦截器 |
| 16 | service.interceptors.request.use( | 25 | service.interceptors.request.use( |
| 17 | config => { | 26 | config => { |
| 18 | // do something before request is sent | 27 | // do something before request is sent |
| 19 | console.log('do something before request is sent') | 28 | // console.log('do something before request is sent') |
| 20 | if (store.getters.token) { | 29 | if (store.getters.token) { |
| 21 | console.log('[X-Token] is a custom headers key') | 30 | // console.log('[X-Token] is a custom headers key') |
| 22 | // let each request carry token | 31 | // let each request carry token |
| 23 | // ['X-Token'] is a custom headers key | 32 | // ['X-Token'] is a custom headers key |
| 24 | // please modify it according to the actual situation | 33 | // please modify it according to the actual situation |
| 25 | config.headers['X-Token'] = getToken() | 34 | config.headers['X-Token'] = getToken(); |
| 35 | config.headers['Content-Type'] = 'application/x-www-form-urlencoded'; | ||
| 36 | // var token = getToken() | ||
| 37 | // Object.assign(config.headers, { 'token': token }) | ||
| 26 | } | 38 | } |
| 27 | return config | 39 | return config |
| 28 | }, | 40 | }, |
| 29 | error => { | 41 | error => { |
| 30 | console.log('do something with request error') | 42 | // console.log('do something with request error') |
| 31 | // do something with request error | 43 | // do something with request error |
| 32 | console.log(error) // for debug | 44 | console.error(error) // for debug |
| 33 | return Promise.reject(error) | 45 | return Promise.reject(error) |
| 34 | } | 46 | } |
| 35 | ) | 47 | ) |
| 36 | 48 | ||
| 37 | // response interceptor | 49 | // response interceptor |
| 38 | // respone拦截器 | 50 | // respone拦截器 |
| 39 | service.interceptors.response.use( | 51 | service.interceptors.response.use( |
| 40 | /** | 52 | /** |
| 41 | * If you want to get http information such as headers or status | 53 | * If you want to get http information such as headers or status |
| 42 | * Please return response => response | 54 | * Please return response => response |
| 43 | */ | 55 | */ |
| 44 | 56 | ||
| 45 | /** | 57 | /** |
| 46 | * Determine the request status by custom code | 58 | * Determine the request status by custom code |
| 47 | * Here is just an example | 59 | * Here is just an example |
| 48 | * You can also judge the status by HTTP Status Code | 60 | * You can also judge the status by HTTP Status Code |
| 49 | */ | 61 | */ |
| 50 | response => { | 62 | response => { |
| 51 | const res = response.data | 63 | const res = response.data |
| 64 | console.log('返回的数据-------->', res); | ||
| 52 | /** | 65 | /** |
| 53 | * 下面的注释为通过response自定义code来标示请求状态,当code返回如下情况为权限有问题,登出并返回到登录页 | 66 | * 下面的注释为通过response自定义code来标示请求状态,当code返回如下情况为权限有问题,登出并返回到登录页 |
| 54 | * 如通过xmlhttprequest 状态码标识 逻辑可写在下面error中 | 67 | * 如通过xmlhttprequest 状态码标识 逻辑可写在下面error中 |
| 55 | */ | 68 | */ |
| 56 | console.log('if the custom code is not 20000, it is judged as an error.') | 69 | // console.log('if the custom code is not 20000, it is judged as an error.') |
| 57 | // if the custom code is not 20000, it is judged as an error. | ||
| 58 | if (res.code !== 20000) { | 70 | if (res.code !== 20000) { |
| 59 | Message({ | 71 | Message({ |
| 60 | message: res.message || 'Error', | 72 | message: res.message || 'Error', |
| 61 | type: 'error', | 73 | type: 'error', |
| 62 | duration: 5 * 1000 | 74 | duration: 5 * 1000 |
| 63 | }) | 75 | }) |
| 64 | 76 | ||
| 65 | // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired; | ||
| 66 | // 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了; | 77 | // 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了; |
| 67 | if (res.code === 50008 || res.code === 50012 || res.code === 50014) { | 78 | if (res.code === 50008 || res.code === 50012 || res.code === 50014) { |
| 68 | // to re-login | 79 | // to re-login |
| 69 | // MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', { | 80 | // MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', { |
| 70 | MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', { | 81 | MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', { |
| 71 | // confirmButtonText: 'Re-Login', | 82 | // confirmButtonText: 'Re-Login', |
| 72 | confirmButtonText: '重新登录', | 83 | confirmButtonText: '重新登录', |
| 73 | // cancelButtonText: 'Cancel', | 84 | // cancelButtonText: 'Cancel', |
| 74 | cancelButtonText: '取消', | 85 | cancelButtonText: '取消', |
| 75 | type: 'warning' | 86 | type: 'warning' |
| 76 | }).then(() => { | 87 | }).then(() => { |
| 77 | store.dispatch('user/resetToken').then(() => { | 88 | store.dispatch('user/resetToken').then(() => { |
| 78 | location.reload()// 为了重新实例化vue-router对象 避免bug | 89 | location.reload() // 为了重新实例化vue-router对象 避免bug |
| 79 | }) | 90 | }) |
| 80 | }) | 91 | }) |
| 81 | } | 92 | } |
| 82 | return Promise.reject(new Error(res.message || 'Error')) | 93 | return Promise.reject(new Error(res.message || 'Error')) |
| 83 | } else { | 94 | } else { |
| 84 | return res | 95 | // const token = res.data.token; |
| 96 | console.log('进入20000号判断-------->', res); | ||
| 97 | return res; | ||
| 85 | } | 98 | } |
| 86 | }, | 99 | }, |
| 87 | error => { | 100 | error => { |
| 88 | console.log('err' + error) // for debug | 101 | console.error('===============发生错误!!!!!===============' + error) // for debug |
| 89 | Message({ | 102 | Message({ |
| 90 | message: error.message, | 103 | message: error.message, |
| 91 | type: 'error', | 104 | type: 'error', |
| 92 | duration: 5 * 1000 | 105 | duration: 5 * 1000 |
| 93 | }) | 106 | }) |
| 94 | return Promise.reject(error) | 107 | return Promise.reject(error) |
| 95 | } | 108 | } |
| 96 | ) | 109 | ) |
| 97 | 110 |
src/views/login/index.vue
| 1 | <template> | 1 | <template> |
| 2 | <div class="login-container"> | 2 | <div class="login-container"> |
| 3 | <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left"> | 3 | <el-form |
| 4 | 4 | ref="loginForm" | |
| 5 | :model="loginForm" | ||
| 6 | :rules="loginRules" | ||
| 7 | class="login-form" | ||
| 8 | auto-complete="on" | ||
| 9 | label-position="left" | ||
| 10 | > | ||
| 5 | <div class="title-container"> | 11 | <div class="title-container"> |
| 6 | <h3 class="title">Login Form</h3> | 12 | <h3 class="title">鱼皮系统</h3> |
| 7 | </div> | 13 | </div> |
| 8 | 14 | ||
| 9 | <el-form-item prop="username"> | 15 | <el-form-item prop="username"> |
| 10 | <span class="svg-container"> | 16 | <span class="svg-container"> |
| 11 | <svg-icon icon-class="user" /> | 17 | <svg-icon icon-class="user" /> |
| 12 | </span> | 18 | </span> |
| 13 | <el-input | 19 | <el-input |
| 14 | ref="username" | 20 | ref="username" |
| 15 | v-model="loginForm.username" | 21 | v-model="loginForm.username" |
| 16 | placeholder="Username" | 22 | placeholder="Username" |
| 17 | name="username" | 23 | name="username" |
| 18 | type="text" | 24 | type="text" |
| 19 | tabindex="1" | 25 | tabindex="1" |
| 20 | auto-complete="on" | 26 | auto-complete="on" |
| 21 | /> | 27 | /> |
| 22 | </el-form-item> | 28 | </el-form-item> |
| 23 | 29 | ||
| 24 | <el-form-item prop="password"> | 30 | <el-form-item prop="password"> |
| 25 | <span class="svg-container"> | 31 | <span class="svg-container"> |
| 26 | <svg-icon icon-class="password" /> | 32 | <svg-icon icon-class="password" /> |
| 27 | </span> | 33 | </span> |
| 28 | <el-input | 34 | <el-input |
| 29 | :key="passwordType" | 35 | :key="passwordType" |
| 30 | ref="password" | 36 | ref="password" |
| 31 | v-model="loginForm.password" | 37 | v-model="loginForm.password" |
| 32 | :type="passwordType" | 38 | :type="passwordType" |
| 33 | placeholder="Password" | 39 | placeholder="Password" |
| 34 | name="password" | 40 | name="password" |
| 35 | tabindex="2" | 41 | tabindex="2" |
| 36 | auto-complete="on" | 42 | auto-complete="on" |
| 37 | @keyup.enter.native="handleLogin" | 43 | @keyup.enter.native="handleLogin" |
| 38 | /> | 44 | /> |
| 39 | <span class="show-pwd" @click="showPwd"> | 45 | <span class="show-pwd" @click="showPwd"> |
| 40 | <svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" /> | 46 | <svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" /> |
| 41 | </span> | 47 | </span> |
| 42 | </el-form-item> | 48 | </el-form-item> |
| 43 | <!-- <el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">reg</el-button> --> | 49 | <!-- <el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">reg</el-button> --> |
| 44 | <el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">Login</el-button> | 50 | <el-button |
| 51 | :loading="loading" | ||
| 52 | type="primary" | ||
| 53 | style="width:100%;margin-bottom:30px;" | ||
| 54 | @click.native.prevent="handleLogin" | ||
| 55 | >Login</el-button> | ||
| 45 | 56 | ||
| 46 | <div class="tips"> | 57 | <div class="tips"> |
| 47 | <span style="margin-right:20px;">username: admin</span> | 58 | <span style="margin-right:20px;">username: admin</span> |
| 48 | <span> password: any</span> | 59 | <span>password: any</span> |
| 49 | </div> | 60 | </div> |
| 50 | |||
| 51 | </el-form> | 61 | </el-form> |
| 52 | </div> | 62 | </div> |
| 53 | </template> | 63 | </template> |
| 54 | 64 | ||
| 55 | <script> | 65 | <script> |
| 56 | import { validUsername } from '@/utils/validate' | 66 | import { validUsername } from "@/utils/validate"; |
| 57 | 67 | ||
| 58 | export default { | 68 | export default { |
| 59 | name: 'Login', | 69 | name: "Login", |
| 60 | data() { | 70 | data() { |
| 61 | const validateUsername = (rule, value, callback) => { | 71 | const validateUsername = (rule, value, callback) => { |
| 62 | if (!validUsername(value)) { | 72 | if (!validUsername(value)) { |
| 63 | callback(new Error('Please enter the correct user name')) | 73 | callback(new Error("Please enter the correct user name")); |
| 64 | } else { | 74 | } else { |
| 65 | callback() | 75 | callback(); |
| 66 | } | 76 | } |
| 67 | } | 77 | }; |
| 68 | const validatePassword = (rule, value, callback) => { | 78 | const validatePassword = (rule, value, callback) => { |
| 69 | if (value.length < 6) { | 79 | if (value.length < 6) { |
| 70 | callback(new Error('The password can not be less than 6 digits')) | 80 | callback(new Error("The password can not be less than 6 digits")); |
| 71 | } else { | 81 | } else { |
| 72 | callback() | 82 | callback(); |
| 73 | } | 83 | } |
| 74 | } | 84 | }; |
| 75 | return { | 85 | return { |
| 76 | loginForm: { | 86 | loginForm: { |
| 77 | username: 'admin', | 87 | username: "admin", |
| 78 | password: '111111' | 88 | password: "111111" |
| 79 | }, | 89 | }, |
| 80 | loginRules: { | 90 | loginRules: { |
| 81 | username: [{ required: true, trigger: 'blur', validator: validateUsername }], | 91 | username: [ |
| 82 | password: [{ required: true, trigger: 'blur', validator: validatePassword }] | 92 | { required: true, trigger: "blur", validator: validateUsername } |
| 93 | ], | ||
| 94 | password: [ | ||
| 95 | { required: true, trigger: "blur", validator: validatePassword } | ||
| 96 | ] | ||
| 83 | }, | 97 | }, |
| 84 | loading: false, | 98 | loading: false, |
| 85 | passwordType: 'password', | 99 | passwordType: "password", |
| 86 | redirect: undefined | 100 | redirect: undefined |
| 87 | } | 101 | }; |
| 88 | }, | 102 | }, |
| 89 | watch: { | 103 | watch: { |
| 90 | $route: { | 104 | $route: { |
| 91 | handler: function(route) { | 105 | handler: function(route) { |
| 92 | this.redirect = route.query && route.query.redirect | 106 | this.redirect = route.query && route.query.redirect; |
| 93 | }, | 107 | }, |
| 94 | immediate: true | 108 | immediate: true |
| 95 | } | 109 | } |
| 96 | }, | 110 | }, |
| 97 | methods: { | 111 | methods: { |
| 98 | showPwd() { | 112 | showPwd() { |
| 99 | if (this.passwordType === 'password') { | 113 | if (this.passwordType === "password") { |
| 100 | this.passwordType = '' | 114 | this.passwordType = ""; |
| 101 | } else { | 115 | } else { |
| 102 | this.passwordType = 'password' | 116 | this.passwordType = "password"; |
| 103 | } | 117 | } |
| 104 | this.$nextTick(() => { | 118 | this.$nextTick(() => { |
| 105 | this.$refs.password.focus() | 119 | this.$refs.password.focus(); |
| 106 | }) | 120 | }); |
| 107 | }, | 121 | }, |
| 108 | handleLogin() { | 122 | handleLogin() { |
| 109 | this.$refs.loginForm.validate(valid => { | 123 | this.$refs.loginForm.validate(valid => { |
| 110 | if (valid) { | 124 | if (valid) { |
| 111 | this.loading = true | 125 | this.loading = true; |
| 112 | this.$store.dispatch('user/login', this.loginForm).then(() => { | 126 | this.$store |
| 113 | this.$router.push({ path: this.redirect || '/' }) | 127 | .dispatch("user/login", this.loginForm) |
| 114 | this.loading = false | 128 | .then(() => { |
| 115 | }).catch(() => { | 129 | this.$router.push({ path: this.redirect || "/" }); |
| 116 | this.loading = false | 130 | this.loading = false; |
| 117 | }) | 131 | console.log('this.redirect', this.$router); |
| 132 | }) | ||
| 133 | .catch(res => { | ||
| 134 | console.log("res error------------>", res); | ||
| 135 | this.loading = false; | ||
| 136 | }); | ||
| 118 | } else { | 137 | } else { |
| 119 | console.log('error submit!!') | 138 | console.log("error submit!!"); |
| 120 | return false | 139 | return false; |
| 121 | } | 140 | } |
| 122 | }) | 141 | }); |
| 123 | } | 142 | } |
| 124 | } | 143 | } |
| 125 | } | 144 | }; |
| 126 | </script> | 145 | </script> |
| 127 | 146 | ||
| 128 | <style lang="scss"> | 147 | <style lang="scss"> |
| 129 | /* 修复input 背景不协调 和光标变色 */ | 148 | /* 修复input 背景不协调 和光标变色 */ |
| 130 | /* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */ | 149 | /* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */ |
| 131 | 150 | ||
| 132 | $bg:#283443; | 151 | $bg: #283443; |
| 133 | $light_gray:#fff; | 152 | $light_gray: #fff; |
| 134 | $cursor: #fff; | 153 | $cursor: #fff; |
| 135 | 154 | ||
| 136 | @supports (-webkit-mask: none) and (not (cater-color: $cursor)) { | 155 | @supports (-webkit-mask: none) and (not (cater-color: $cursor)) { |
| 137 | .login-container .el-input input { | 156 | .login-container .el-input input { |
| 138 | color: $cursor; | 157 | color: $cursor; |
| 139 | } | 158 | } |
| 140 | } | 159 | } |
| 141 | 160 | ||
| 142 | /* reset element-ui css */ | 161 | /* reset element-ui css */ |
| 143 | .login-container { | 162 | .login-container { |
| 144 | .el-input { | 163 | .el-input { |
| 145 | display: inline-block; | 164 | display: inline-block; |
| 146 | height: 47px; | 165 | height: 47px; |
| 147 | width: 85%; | 166 | width: 85%; |
| 148 | 167 | ||
| 149 | input { | 168 | input { |
| 150 | background: transparent; | 169 | background: transparent; |
| 151 | border: 0px; | 170 | border: 0px; |
| 152 | -webkit-appearance: none; | 171 | -webkit-appearance: none; |
| 153 | border-radius: 0px; | 172 | border-radius: 0px; |
| 154 | padding: 12px 5px 12px 15px; | 173 | padding: 12px 5px 12px 15px; |
| 155 | color: $light_gray; | 174 | color: $light_gray; |
| 156 | height: 47px; | 175 | height: 47px; |
| 157 | caret-color: $cursor; | 176 | caret-color: $cursor; |
| 158 | 177 | ||
| 159 | &:-webkit-autofill { | 178 | &:-webkit-autofill { |
| 160 | box-shadow: 0 0 0px 1000px $bg inset !important; | 179 | box-shadow: 0 0 0px 1000px $bg inset !important; |
| 161 | -webkit-text-fill-color: $cursor !important; | 180 | -webkit-text-fill-color: $cursor !important; |
| 162 | } | 181 | } |
| 163 | } | 182 | } |
| 164 | } | 183 | } |
| 165 | 184 | ||
| 166 | .el-form-item { | 185 | .el-form-item { |
| 167 | border: 1px solid rgba(255, 255, 255, 0.1); | 186 | border: 1px solid rgba(255, 255, 255, 0.1); |
| 168 | background: rgba(0, 0, 0, 0.1); | 187 | background: rgba(0, 0, 0, 0.1); |
| 169 | border-radius: 5px; | 188 | border-radius: 5px; |
| 170 | color: #454545; | 189 | color: #454545; |
| 171 | } | 190 | } |
| 172 | } | 191 | } |
| 173 | </style> | 192 | </style> |
| 174 | 193 | ||
| 175 | <style lang="scss" scoped> | 194 | <style lang="scss" scoped> |
| 176 | $bg:#2d3a4b; | 195 | $bg: #2d3a4b; |
| 177 | $dark_gray:#889aa4; | 196 | $dark_gray: #889aa4; |
| 178 | $light_gray:#eee; | 197 | $light_gray: #eee; |
| 179 | 198 | ||
| 180 | .login-container { | 199 | .login-container { |
| 181 | min-height: 100%; | 200 | min-height: 100%; |
| 182 | width: 100%; | 201 | width: 100%; |
| 183 | background-color: $bg; | 202 | background-color: $bg; |
| 184 | overflow: hidden; | 203 | overflow: hidden; |
| 185 | 204 | ||
| 186 | .login-form { | 205 | .login-form { |
| 187 | position: relative; | 206 | position: relative; |
| 188 | width: 520px; | 207 | width: 520px; |
| 189 | max-width: 100%; | 208 | max-width: 100%; |
| 190 | padding: 160px 35px 0; | 209 | padding: 160px 35px 0; |
| 191 | margin: 0 auto; | 210 | margin: 0 auto; |
| 192 | overflow: hidden; | 211 | overflow: hidden; |
| 193 | } | 212 | } |
| 194 | 213 | ||
| 195 | .tips { | 214 | .tips { |
| 196 | font-size: 14px; | 215 | font-size: 14px; |
| 197 | color: #fff; | 216 | color: #fff; |
| 198 | margin-bottom: 10px; | 217 | margin-bottom: 10px; |
| 199 | 218 | ||
| 200 | span { | 219 | span { |
| 201 | &:first-of-type { | 220 | &:first-of-type { |
| 202 | margin-right: 16px; | 221 | margin-right: 16px; |
| 203 | } | 222 | } |
| 204 | } | 223 | } |
| 205 | } | 224 | } |
| 206 | 225 | ||
| 207 | .svg-container { | 226 | .svg-container { |
| 208 | padding: 6px 5px 6px 15px; | 227 | padding: 6px 5px 6px 15px; |
| 209 | color: $dark_gray; | 228 | color: $dark_gray; |
| 210 | vertical-align: middle; | 229 | vertical-align: middle; |
| 211 | width: 30px; | 230 | width: 30px; |
| 212 | display: inline-block; | 231 | display: inline-block; |
| 213 | } | 232 | } |
| 214 | 233 | ||
| 215 | .title-container { | 234 | .title-container { |
| 216 | position: relative; | 235 | position: relative; |
| 217 | 236 | ||
| 218 | .title { | 237 | .title { |
| 219 | font-size: 26px; | 238 | font-size: 26px; |
| 220 | color: $light_gray; | 239 | color: $light_gray; |
| 221 | margin: 0px auto 40px auto; | 240 | margin: 0px auto 40px auto; |
| 222 | text-align: center; | 241 | text-align: center; |
| 223 | font-weight: bold; | 242 | font-weight: bold; |
| 224 | } | 243 | } |
| 225 | } | 244 | } |
| 226 | 245 | ||
| 227 | .show-pwd { | 246 | .show-pwd { |
| 228 | position: absolute; | 247 | position: absolute; |
| 229 | right: 10px; | 248 | right: 10px; |
| 230 | top: 7px; | 249 | top: 7px; |
| 231 | font-size: 16px; | 250 | font-size: 16px; |
| 232 | color: $dark_gray; | 251 | color: $dark_gray; |
| 233 | cursor: pointer; | 252 | cursor: pointer; |
| 234 | user-select: none; | 253 | user-select: none; |
| 235 | } | 254 | } |
| 236 | } | 255 | } |
| 237 | </style> | 256 | </style> |
vue.config.js
| 1 | 'use strict' | 1 | 'use strict' |
| 2 | const path = require('path') | 2 | const path = require('path') |
| 3 | const defaultSettings = require('./src/settings.js') | 3 | const defaultSettings = require('./src/settings.js') |
| 4 | 4 | ||
| 5 | function resolve(dir) { | 5 | function resolve(dir) { |
| 6 | return path.join(__dirname, dir) | 6 | return path.join(__dirname, dir) |
| 7 | } | 7 | } |
| 8 | 8 | ||
| 9 | const name = defaultSettings.title || 'vue Admin Template' // page title | 9 | const name = defaultSettings.title || 'vue Admin Template' // page title |
| 10 | 10 | ||
| 11 | // If your port is set to 80, | 11 | // If your port is set to 80, |
| 12 | // use administrator privileges to execute the command line. | 12 | // use administrator privileges to execute the command line. |
| 13 | // For example, Mac: sudo npm run | 13 | // For example, Mac: sudo npm run |
| 14 | // You can change the port by the following methods: | 14 | // You can change the port by the following methods: |
| 15 | // port = 9528 npm run dev OR npm run dev --port = 9528 | 15 | // port = 9528 npm run dev OR npm run dev --port = 9528 |
| 16 | const port = process.env.port || process.env.npm_config_port || 9528 // dev port | 16 | const port = process.env.port || process.env.npm_config_port || 9528 // dev port |
| 17 | 17 | ||
| 18 | // All configuration item explanations can be find in https://cli.vuejs.org/config/ | 18 | // All configuration item explanations can be find in https://cli.vuejs.org/config/ |
| 19 | module.exports = { | 19 | module.exports = { |
| 20 | /** | 20 | /** |
| 21 | * You will need to set publicPath if you plan to deploy your site under a sub path, | 21 | * You will need to set publicPath if you plan to deploy your site under a sub path, |
| 22 | * for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/, | 22 | * for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/, |
| 23 | * then publicPath should be set to "/bar/". | 23 | * then publicPath should be set to "/bar/". |
| 24 | * In most cases please use '/' !!! | 24 | * In most cases please use '/' !!! |
| 25 | * Detail: https://cli.vuejs.org/config/#publicpath | 25 | * Detail: https://cli.vuejs.org/config/#publicpath |
| 26 | */ | 26 | */ |
| 27 | publicPath: '/', | 27 | publicPath: '/', |
| 28 | outputDir: 'dist', | 28 | outputDir: 'dist', |
| 29 | assetsDir: 'static', | 29 | assetsDir: 'static', |
| 30 | lintOnSave: process.env.NODE_ENV === 'development', | 30 | lintOnSave: process.env.NODE_ENV === 'development', |
| 31 | productionSourceMap: false, | 31 | productionSourceMap: false, |
| 32 | devServer: { | 32 | devServer: { |
| 33 | port: port, | 33 | port: port, |
| 34 | open: true, | 34 | open: true, |
| 35 | overlay: { | 35 | overlay: { |
| 36 | warnings: false, | 36 | warnings: false, |
| 37 | errors: true | 37 | errors: true |
| 38 | }, | 38 | }, |
| 39 | before: require('./mock/mock-server.js') | 39 | before: require('./mock/mock-server.js') |
| 40 | }, | 40 | }, |
| 41 | configureWebpack: { | 41 | configureWebpack: { |
| 42 | // provide the app's title in webpack's name field, so that | 42 | // provide the app's title in webpack's name field, so that |
| 43 | // it can be accessed in index.html to inject the correct title. | 43 | // it can be accessed in index.html to inject the correct title. |
| 44 | name: name, | 44 | name: name, |
| 45 | resolve: { | 45 | resolve: { |
| 46 | alias: { | 46 | alias: { |
| 47 | '@': resolve('src') | 47 | '@': resolve('src') |
| 48 | } | 48 | } |
| 49 | } | 49 | } |
| 50 | }, | 50 | }, |
| 51 | chainWebpack(config) { | 51 | chainWebpack(config) { |
| 52 | config.plugins.delete('preload') // TODO: need test | 52 | config.plugins.delete('preload') // TODO: need test |
| 53 | config.plugins.delete('prefetch') // TODO: need test | 53 | config.plugins.delete('prefetch') // TODO: need test |
| 54 | 54 | ||
| 55 | // set svg-sprite-loader | 55 | // set svg-sprite-loader |
| 56 | config.module | 56 | config.module |
| 57 | .rule('svg') | 57 | .rule('svg') |
| 58 | .exclude.add(resolve('src/icons')) | 58 | .exclude.add(resolve('src/icons')) |
| 59 | .end() | 59 | .end() |
| 60 | config.module | 60 | config.module |
| 61 | .rule('icons') | 61 | .rule('icons') |
| 62 | .test(/\.svg$/) | 62 | .test(/\.svg$/) |
| 63 | .include.add(resolve('src/icons')) | 63 | .include.add(resolve('src/icons')) |
| 64 | .end() | 64 | .end() |
| 65 | .use('svg-sprite-loader') | 65 | .use('svg-sprite-loader') |
| 66 | .loader('svg-sprite-loader') | 66 | .loader('svg-sprite-loader') |
| 67 | .options({ | 67 | .options({ |
| 68 | symbolId: 'icon-[name]' | 68 | symbolId: 'icon-[name]' |
| 69 | }) | 69 | }) |
| 70 | .end() | 70 | .end() |
| 71 | 71 | ||
| 72 | // set preserveWhitespace | 72 | // set preserveWhitespace |
| 73 | config.module | 73 | config.module |
| 74 | .rule('vue') | 74 | .rule('vue') |
| 75 | .use('vue-loader') | 75 | .use('vue-loader') |
| 76 | .loader('vue-loader') | 76 | .loader('vue-loader') |
| 77 | .tap(options => { | 77 | .tap(options => { |
| 78 | options.compilerOptions.preserveWhitespace = true | 78 | options.compilerOptions.preserveWhitespace = true |
| 79 | return options | 79 | return options |
| 80 | }) | 80 | }) |
| 81 | .end() | 81 | .end() |
| 82 | 82 | ||
| 83 | config | 83 | config |
| 84 | // https://webpack.js.org/configuration/devtool/#development | 84 | // https://webpack.js.org/configuration/devtool/#development |
| 85 | .when(process.env.NODE_ENV === 'development', | 85 | .when(process.env.NODE_ENV === 'development', |
| 86 | config => config.devtool('cheap-source-map') | 86 | config => config.devtool('cheap-source-map') |
| 87 | ) | 87 | ) |
| 88 | 88 | ||
| 89 | config | 89 | config |
| 90 | .when(process.env.NODE_ENV !== 'development', | 90 | .when(process.env.NODE_ENV !== 'development', |
| 91 | config => { | 91 | config => { |
| 92 | config | 92 | config |
| 93 | .plugin('ScriptExtHtmlWebpackPlugin') | 93 | .plugin('ScriptExtHtmlWebpackPlugin') |
| 94 | .after('html') | 94 | .after('html') |
| 95 | .use('script-ext-html-webpack-plugin', [{ | 95 | .use('script-ext-html-webpack-plugin', [{ |
| 96 | // `runtime` must same as runtimeChunk name. default is `runtime` | 96 | // `runtime` must same as runtimeChunk name. default is `runtime` |
| 97 | inline: /runtime\..*\.js$/ | 97 | inline: /runtime\..*\.js$/ |
| 98 | }]) | 98 | }]) |
| 99 | .end() | 99 | .end() |
| 100 | config | 100 | config |
| 101 | .optimization.splitChunks({ | 101 | .optimization.splitChunks({ |
| 102 | chunks: 'all', | 102 | chunks: 'all', |
| 103 | cacheGroups: { | 103 | cacheGroups: { |
| 104 | libs: { | 104 | libs: { |
| 105 | name: 'chunk-libs', | 105 | name: 'chunk-libs', |
| 106 | test: /[\\/]node_modules[\\/]/, | 106 | test: /[\\/]node_modules[\\/]/, |
| 107 | priority: 10, | 107 | priority: 10, |
| 108 | chunks: 'initial' // only package third parties that are initially dependent | 108 | chunks: 'initial' // only package third parties that are initially dependent |
| 109 | }, | 109 | }, |
| 110 | elementUI: { | 110 | elementUI: { |
| 111 | name: 'chunk-elementUI', // split elementUI into a single package | 111 | name: 'chunk-elementUI', // split elementUI into a single package |
| 112 | priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app | 112 | priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app |
| 113 | test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm | 113 | test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm |
| 114 | }, | 114 | }, |
| 115 | commons: { | 115 | commons: { |
| 116 | name: 'chunk-commons', | 116 | name: 'chunk-commons', |
| 117 | test: resolve('src/components'), // can customize your rules | 117 | test: resolve('src/components'), // can customize your rules |
| 118 | minChunks: 3, // minimum common number | 118 | minChunks: 3, // minimum common number |
| 119 | priority: 5, | 119 | priority: 5, |
| 120 | reuseExistingChunk: true | 120 | reuseExistingChunk: true |
| 121 | } | 121 | } |
| 122 | } | 122 | } |
| 123 | }) | 123 | }) |
| 124 | config.optimization.runtimeChunk('single') | 124 | config.optimization.runtimeChunk('single') |
| 125 | } | 125 | } |
| 126 | ) | 126 | ) |
| 127 | } | 127 | } |
| 128 | } | 128 | } |
| 129 | 129 |