Compare commits
64 Commits
Author | SHA1 | Date |
---|---|---|
|
4c18a3f47b | |
|
714ded1155 | |
|
785f19f551 | |
|
75ba8cf038 | |
|
abcd5d810d | |
|
8c4e38fb1f | |
|
fe326aa2b0 | |
|
c9cb7db3ce | |
|
cd8d52bfbd | |
|
879318692c | |
|
8e76fdb622 | |
|
129ea7e654 | |
|
83f3a9cc57 | |
|
b292e46f45 | |
|
4958db1bad | |
|
88303a2959 | |
|
8865514c81 | |
|
e2fd7c7528 | |
|
5c87772025 | |
|
efc976ae5a | |
|
8f2c04e60c | |
|
e1c24e7e85 | |
|
4a822b95d6 | |
|
aff349a863 | |
|
00c68bc5cd | |
|
ad02035220 | |
|
fc7c3f1da4 | |
|
97290e6f49 | |
|
4502d3ebc7 | |
|
d0518bce5b | |
|
95c7bf5d10 | |
|
227ca9b649 | |
|
d4c29f903f | |
|
bc94111867 | |
|
9cf3082659 | |
|
f70f0675ba | |
|
6169577990 | |
|
dc5aa51577 | |
|
35ea50deea | |
|
5afac23d2f | |
|
f32b49e662 | |
|
0e8fa65568 | |
|
65730989c4 | |
|
00bfe07dc7 | |
|
44c0d705c5 | |
|
b9202ade9b | |
|
737d9fc9ee | |
|
3d9ec1b729 | |
|
cb9d1c0989 | |
|
7aef039149 | |
|
ca46b22204 | |
|
969f43415d | |
|
0353f1a4be | |
|
1e2cf43a4f | |
|
79eeed7d59 | |
|
fa7310902a | |
|
b6753d0373 | |
|
ac4865ab2d | |
|
9793fff12d | |
|
896962a5c5 | |
|
d482e0bb9f | |
|
16d39eb015 | |
|
74da10ca29 | |
|
b2fe1a22e1 |
|
@ -3,12 +3,3 @@ ENV = 'development'
|
||||||
|
|
||||||
# base api
|
# base api
|
||||||
VUE_APP_BASE_API = '/dev-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
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
language: node_js
|
language: node_js
|
||||||
node_js: stable
|
node_js: 10
|
||||||
script: npm run test
|
script: npm run test
|
||||||
notifications:
|
notifications:
|
||||||
email: false
|
email: false
|
||||||
|
|
21
README-zh.md
21
README-zh.md
|
@ -8,17 +8,28 @@
|
||||||
|
|
||||||
目前版本为 `v4.0+` 基于 `vue-cli` 进行构建,若你想使用旧版本,可以切换分支到[tag/3.11.0](https://github.com/PanJiaChen/vue-admin-template/tree/tag/3.11.0),它不依赖 `vue-cli`。
|
目前版本为 `v4.0+` 基于 `vue-cli` 进行构建,若你想使用旧版本,可以切换分支到[tag/3.11.0](https://github.com/PanJiaChen/vue-admin-template/tree/tag/3.11.0),它不依赖 `vue-cli`。
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<b>SPONSORED BY</b>
|
||||||
|
</p>
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://finclip.com?from=vue_element" title="FinClip" target="_blank">
|
||||||
|
<img height="200px" src="https://gitee.com/panjiachen/gitee-cdn/raw/master/vue%E8%B5%9E%E5%8A%A9.png" title="FinClip">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
## Extra
|
## Extra
|
||||||
|
|
||||||
如果你想要根据用户角色来动态生成侧边栏和 router,你可以使用该分支[permission-control](https://github.com/PanJiaChen/vue-admin-template/tree/permission-control)
|
如果你想要根据用户角色来动态生成侧边栏和 router,你可以使用该分支[permission-control](https://github.com/PanJiaChen/vue-admin-template/tree/permission-control)
|
||||||
|
|
||||||
## 相关项目
|
## 相关项目
|
||||||
|
|
||||||
[vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
|
- [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
|
||||||
|
|
||||||
[electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
|
- [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
|
||||||
|
|
||||||
[vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template)
|
- [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template)
|
||||||
|
|
||||||
|
- [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312)
|
||||||
|
|
||||||
写了一个系列的教程配套文章,如何从零构建后一个完整的后台项目:
|
写了一个系列的教程配套文章,如何从零构建后一个完整的后台项目:
|
||||||
|
|
||||||
|
@ -77,6 +88,10 @@ npm run lint -- --fix
|
||||||
|
|
||||||
更多信息请参考 [使用文档](https://panjiachen.github.io/vue-element-admin-site/zh/)
|
更多信息请参考 [使用文档](https://panjiachen.github.io/vue-element-admin-site/zh/)
|
||||||
|
|
||||||
|
## 购买贴纸
|
||||||
|
|
||||||
|
你也可以通过 购买[官方授权的贴纸](https://smallsticker.com/product/vue-element-admin) 的方式来支持 vue-element-admin - 每售出一张贴纸,我们将获得 2 元的捐赠。
|
||||||
|
|
||||||
## Demo
|
## Demo
|
||||||
|
|
||||||

|

|
||||||
|
|
20
README.md
20
README.md
|
@ -9,8 +9,16 @@ English | [简体中文](./README-zh.md)
|
||||||
|
|
||||||
**The current version is `v4.0+` build on `vue-cli`. If you want to use the old version , you can switch branch to [tag/3.11.0](https://github.com/PanJiaChen/vue-admin-template/tree/tag/3.11.0), it does not rely on `vue-cli`**
|
**The current version is `v4.0+` build on `vue-cli`. If you want to use the old version , you can switch branch to [tag/3.11.0](https://github.com/PanJiaChen/vue-admin-template/tree/tag/3.11.0), it does not rely on `vue-cli`**
|
||||||
|
|
||||||
## Build Setup
|
<p align="center">
|
||||||
|
<b>SPONSORED BY</b>
|
||||||
|
</p>
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://finclip.com?from=vue_element" title="FinClip" target="_blank">
|
||||||
|
<img height="200px" src="https://gitee.com/panjiachen/gitee-cdn/raw/master/vue%E8%B5%9E%E5%8A%A9.png" title="FinClip">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## Build Setup
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# clone the project
|
# clone the project
|
||||||
|
@ -26,7 +34,7 @@ npm install
|
||||||
npm run dev
|
npm run dev
|
||||||
```
|
```
|
||||||
|
|
||||||
This will automatically open http://localhost:9527
|
This will automatically open http://localhost:9528
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
|
@ -68,11 +76,13 @@ For `typescript` version, you can use [vue-typescript-admin-template](https://gi
|
||||||
|
|
||||||
## Related Project
|
## Related Project
|
||||||
|
|
||||||
[vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
|
- [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
|
||||||
|
|
||||||
[electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
|
- [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
|
||||||
|
|
||||||
[vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template)
|
- [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template)
|
||||||
|
|
||||||
|
- [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312)
|
||||||
|
|
||||||
## Browsers support
|
## Browsers support
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,14 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
presets: [
|
presets: [
|
||||||
'@vue/app'
|
// https://github.com/vuejs/vue-cli/tree/master/packages/@vue/babel-preset-app
|
||||||
]
|
'@vue/cli-plugin-babel/preset'
|
||||||
|
],
|
||||||
|
'env': {
|
||||||
|
'development': {
|
||||||
|
// babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require().
|
||||||
|
// This plugin can significantly increase the speed of hot updates, when you have a large number of pages.
|
||||||
|
// https://panjiachen.github.io/vue-element-admin-site/guide/advanced/lazy-loading.html
|
||||||
|
'plugins': ['dynamic-import-node']
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "./",
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["src/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"exclude": ["node_modules", "dist"]
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
import Mock from 'mockjs'
|
const Mock = require('mockjs')
|
||||||
import { param2Obj } from '../src/utils'
|
const { param2Obj } = require('./utils')
|
||||||
|
|
||||||
import user from './user'
|
const user = require('./user')
|
||||||
import table from './table'
|
const table = require('./table')
|
||||||
|
|
||||||
const mocks = [
|
const mocks = [
|
||||||
...user,
|
...user,
|
||||||
|
@ -12,7 +12,7 @@ const mocks = [
|
||||||
// for front mock
|
// for front mock
|
||||||
// please use it cautiously, it will redefine XMLHttpRequest,
|
// please use it cautiously, it will redefine XMLHttpRequest,
|
||||||
// which will cause many of your third-party libraries to be invalidated(like progress event).
|
// which will cause many of your third-party libraries to be invalidated(like progress event).
|
||||||
export function mockXHR() {
|
function mockXHR() {
|
||||||
// mock patch
|
// mock patch
|
||||||
// https://github.com/nuysoft/Mock/issues/300
|
// https://github.com/nuysoft/Mock/issues/300
|
||||||
Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
|
Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
|
||||||
|
@ -50,17 +50,8 @@ export function mockXHR() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// for mock server
|
module.exports = {
|
||||||
const responseFake = (url, type, respond) => {
|
mocks,
|
||||||
return {
|
mockXHR
|
||||||
url: new RegExp(`/mock${url}`),
|
|
||||||
type: type || 'get',
|
|
||||||
response(req, res) {
|
|
||||||
res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default mocks.map(route => {
|
|
||||||
return responseFake(route.url, route.type, route.response)
|
|
||||||
})
|
|
||||||
|
|
|
@ -2,17 +2,21 @@ const chokidar = require('chokidar')
|
||||||
const bodyParser = require('body-parser')
|
const bodyParser = require('body-parser')
|
||||||
const chalk = require('chalk')
|
const chalk = require('chalk')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
const Mock = require('mockjs')
|
||||||
|
|
||||||
const mockDir = path.join(process.cwd(), 'mock')
|
const mockDir = path.join(process.cwd(), 'mock')
|
||||||
|
|
||||||
function registerRoutes(app) {
|
function registerRoutes(app) {
|
||||||
let mockLastIndex
|
let mockLastIndex
|
||||||
const { default: mocks } = require('./index.js')
|
const { mocks } = require('./index.js')
|
||||||
for (const mock of mocks) {
|
const mocksForServer = mocks.map(route => {
|
||||||
|
return responseFake(route.url, route.type, route.response)
|
||||||
|
})
|
||||||
|
for (const mock of mocksForServer) {
|
||||||
app[mock.type](mock.url, mock.response)
|
app[mock.type](mock.url, mock.response)
|
||||||
mockLastIndex = app._router.stack.length
|
mockLastIndex = app._router.stack.length
|
||||||
}
|
}
|
||||||
const mockRoutesLength = Object.keys(mocks).length
|
const mockRoutesLength = Object.keys(mocksForServer).length
|
||||||
return {
|
return {
|
||||||
mockRoutesLength: mockRoutesLength,
|
mockRoutesLength: mockRoutesLength,
|
||||||
mockStartIndex: mockLastIndex - mockRoutesLength
|
mockStartIndex: mockLastIndex - mockRoutesLength
|
||||||
|
@ -27,10 +31,19 @@ function unregisterRoutes() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = app => {
|
// for mock server
|
||||||
// es6 polyfill
|
const responseFake = (url, type, respond) => {
|
||||||
require('@babel/register')
|
return {
|
||||||
|
url: new RegExp(`${process.env.VUE_APP_BASE_API}${url}`),
|
||||||
|
type: type || 'get',
|
||||||
|
response(req, res) {
|
||||||
|
console.log('request invoke:' + req.path)
|
||||||
|
res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = app => {
|
||||||
// parse app.body
|
// parse app.body
|
||||||
// https://expressjs.com/en/4x/api.html#req.body
|
// https://expressjs.com/en/4x/api.html#req.body
|
||||||
app.use(bodyParser.json())
|
app.use(bodyParser.json())
|
||||||
|
@ -48,6 +61,7 @@ module.exports = app => {
|
||||||
ignoreInitial: true
|
ignoreInitial: true
|
||||||
}).on('all', (event, path) => {
|
}).on('all', (event, path) => {
|
||||||
if (event === 'change' || event === 'add') {
|
if (event === 'change' || event === 'add') {
|
||||||
|
try {
|
||||||
// remove mock routes stack
|
// remove mock routes stack
|
||||||
app._router.stack.splice(mockStartIndex, mockRoutesLength)
|
app._router.stack.splice(mockStartIndex, mockRoutesLength)
|
||||||
|
|
||||||
|
@ -59,6 +73,9 @@ module.exports = app => {
|
||||||
mockStartIndex = mockRoutes.mockStartIndex
|
mockStartIndex = mockRoutes.mockStartIndex
|
||||||
|
|
||||||
console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed ${path}`))
|
console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed ${path}`))
|
||||||
|
} catch (error) {
|
||||||
|
console.log(chalk.redBright(error))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import Mock from 'mockjs'
|
const Mock = require('mockjs')
|
||||||
|
|
||||||
const data = Mock.mock({
|
const data = Mock.mock({
|
||||||
'items|30': [{
|
'items|30': [{
|
||||||
|
@ -11,9 +11,9 @@ const data = Mock.mock({
|
||||||
}]
|
}]
|
||||||
})
|
})
|
||||||
|
|
||||||
export default [
|
module.exports = [
|
||||||
{
|
{
|
||||||
url: '/table/list',
|
url: '/vue-admin-template/table/list',
|
||||||
type: 'get',
|
type: 'get',
|
||||||
response: config => {
|
response: config => {
|
||||||
const items = data.items
|
const items = data.items
|
||||||
|
|
|
@ -23,10 +23,10 @@ const users = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default [
|
module.exports = [
|
||||||
// user login
|
// user login
|
||||||
{
|
{
|
||||||
url: '/user/login',
|
url: '/vue-admin-template/user/login',
|
||||||
type: 'post',
|
type: 'post',
|
||||||
response: config => {
|
response: config => {
|
||||||
const { username } = config.body
|
const { username } = config.body
|
||||||
|
@ -49,7 +49,7 @@ export default [
|
||||||
|
|
||||||
// get user info
|
// get user info
|
||||||
{
|
{
|
||||||
url: '/user/info\.*',
|
url: '/vue-admin-template/user/info\.*',
|
||||||
type: 'get',
|
type: 'get',
|
||||||
response: config => {
|
response: config => {
|
||||||
const { token } = config.query
|
const { token } = config.query
|
||||||
|
@ -72,7 +72,7 @@ export default [
|
||||||
|
|
||||||
// user logout
|
// user logout
|
||||||
{
|
{
|
||||||
url: '/user/logout',
|
url: '/vue-admin-template/user/logout',
|
||||||
type: 'post',
|
type: 'post',
|
||||||
response: _ => {
|
response: _ => {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
/**
|
||||||
|
* @param {string} url
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
function param2Obj(url) {
|
||||||
|
const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
|
||||||
|
if (!search) {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
const obj = {}
|
||||||
|
const searchArr = search.split('&')
|
||||||
|
searchArr.forEach(v => {
|
||||||
|
const index = v.indexOf('=')
|
||||||
|
if (index !== -1) {
|
||||||
|
const name = v.substring(0, index)
|
||||||
|
const val = v.substring(index + 1, v.length)
|
||||||
|
obj[name] = val
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
param2Obj
|
||||||
|
}
|
50
package.json
50
package.json
|
@ -1,22 +1,22 @@
|
||||||
{
|
{
|
||||||
"name": "vue-admin-template",
|
"name": "vue-admin-template",
|
||||||
"version": "4.1.0",
|
"version": "4.4.0",
|
||||||
"description": "A vue admin template with Element UI & axios & iconfont & permission control & lint",
|
"description": "A vue admin template with Element UI & axios & iconfont & permission control & lint",
|
||||||
"author": "Pan <panfree23@gmail.com>",
|
"author": "Pan <panfree23@gmail.com>",
|
||||||
"license": "MIT",
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vue-cli-service serve",
|
"dev": "vue-cli-service serve",
|
||||||
"build:prod": "vue-cli-service build",
|
"build:prod": "vue-cli-service build",
|
||||||
"build:stage": "vue-cli-service build --mode staging",
|
"build:stage": "vue-cli-service build --mode staging",
|
||||||
"preview": "node build/index.js --preview",
|
"preview": "node build/index.js --preview",
|
||||||
|
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
|
||||||
"lint": "eslint --ext .js,.vue src",
|
"lint": "eslint --ext .js,.vue src",
|
||||||
"test:unit": "jest --clearCache && vue-cli-service test:unit",
|
"test:unit": "jest --clearCache && vue-cli-service test:unit",
|
||||||
"test:ci": "npm run lint && npm run test:unit",
|
"test:ci": "npm run lint && npm run test:unit"
|
||||||
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "0.18.0",
|
"axios": "0.18.1",
|
||||||
"element-ui": "2.7.2",
|
"core-js": "3.6.5",
|
||||||
|
"element-ui": "2.13.2",
|
||||||
"js-cookie": "2.2.0",
|
"js-cookie": "2.2.0",
|
||||||
"normalize.css": "7.0.0",
|
"normalize.css": "7.0.0",
|
||||||
"nprogress": "0.2.0",
|
"nprogress": "0.2.0",
|
||||||
|
@ -26,39 +26,37 @@
|
||||||
"vuex": "3.1.0"
|
"vuex": "3.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "7.0.0",
|
"@vue/cli-plugin-babel": "4.4.4",
|
||||||
"@babel/register": "7.0.0",
|
"@vue/cli-plugin-eslint": "4.4.4",
|
||||||
"@vue/cli-plugin-babel": "3.6.0",
|
"@vue/cli-plugin-unit-jest": "4.4.4",
|
||||||
"@vue/cli-plugin-eslint": "3.6.0",
|
"@vue/cli-service": "4.4.4",
|
||||||
"@vue/cli-plugin-unit-jest": "3.6.3",
|
|
||||||
"@vue/cli-service": "3.6.0",
|
|
||||||
"@vue/test-utils": "1.0.0-beta.29",
|
"@vue/test-utils": "1.0.0-beta.29",
|
||||||
"babel-core": "7.0.0-bridge.0",
|
"autoprefixer": "9.5.1",
|
||||||
"babel-eslint": "10.0.1",
|
"babel-eslint": "10.1.0",
|
||||||
"babel-jest": "23.6.0",
|
"babel-jest": "23.6.0",
|
||||||
|
"babel-plugin-dynamic-import-node": "2.3.3",
|
||||||
"chalk": "2.4.2",
|
"chalk": "2.4.2",
|
||||||
"connect": "3.6.6",
|
"connect": "3.6.6",
|
||||||
"eslint": "5.15.3",
|
"eslint": "6.7.2",
|
||||||
"eslint-plugin-vue": "5.2.2",
|
"eslint-plugin-vue": "6.2.2",
|
||||||
"html-webpack-plugin": "3.2.0",
|
"html-webpack-plugin": "3.2.0",
|
||||||
"mockjs": "1.0.1-beta3",
|
"mockjs": "1.0.1-beta3",
|
||||||
"node-sass": "^4.9.0",
|
"runjs": "4.3.2",
|
||||||
"runjs": "^4.3.2",
|
"sass": "1.26.8",
|
||||||
"sass-loader": "^7.1.0",
|
"sass-loader": "8.0.2",
|
||||||
"script-ext-html-webpack-plugin": "2.1.3",
|
"script-ext-html-webpack-plugin": "2.1.3",
|
||||||
"script-loader": "0.7.2",
|
"serve-static": "1.13.2",
|
||||||
"serve-static": "^1.13.2",
|
|
||||||
"svg-sprite-loader": "4.1.3",
|
"svg-sprite-loader": "4.1.3",
|
||||||
"svgo": "1.2.2",
|
"svgo": "1.2.2",
|
||||||
"vue-template-compiler": "2.6.10"
|
"vue-template-compiler": "2.6.10"
|
||||||
},
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"> 1%",
|
||||||
|
"last 2 versions"
|
||||||
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8.9",
|
"node": ">=8.9",
|
||||||
"npm": ">= 3.0.0"
|
"npm": ">= 3.0.0"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"license": "MIT"
|
||||||
"> 1%",
|
|
||||||
"last 2 versions",
|
|
||||||
"not ie <= 8"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import request from '@/utils/request'
|
||||||
|
|
||||||
export function getList(params) {
|
export function getList(params) {
|
||||||
return request({
|
return request({
|
||||||
url: '/table/list',
|
url: '/vue-admin-template/table/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params
|
params
|
||||||
})
|
})
|
||||||
|
|
|
@ -2,7 +2,7 @@ import request from '@/utils/request'
|
||||||
|
|
||||||
export function login(data) {
|
export function login(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/user/login',
|
url: '/vue-admin-template/user/login',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
|
@ -10,7 +10,7 @@ export function login(data) {
|
||||||
|
|
||||||
export function getInfo(token) {
|
export function getInfo(token) {
|
||||||
return request({
|
return request({
|
||||||
url: '/user/info',
|
url: '/vue-admin-template/user/info',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: { token }
|
params: { token }
|
||||||
})
|
})
|
||||||
|
@ -18,7 +18,7 @@ export function getInfo(token) {
|
||||||
|
|
||||||
export function logout() {
|
export function logout() {
|
||||||
return request({
|
return request({
|
||||||
url: '/user/logout',
|
url: '/vue-admin-template/user/logout',
|
||||||
method: 'post'
|
method: 'post'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<svg :class="svgClass" aria-hidden="true" v-on="$listeners">
|
<div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
|
||||||
|
<svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
|
||||||
<use :xlink:href="iconName" />
|
<use :xlink:href="iconName" />
|
||||||
</svg>
|
</svg>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage
|
||||||
|
import { isExternal } from '@/utils/validate'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'SvgIcon',
|
name: 'SvgIcon',
|
||||||
props: {
|
props: {
|
||||||
|
@ -18,6 +22,9 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
isExternal() {
|
||||||
|
return isExternal(this.iconClass)
|
||||||
|
},
|
||||||
iconName() {
|
iconName() {
|
||||||
return `#icon-${this.iconClass}`
|
return `#icon-${this.iconClass}`
|
||||||
},
|
},
|
||||||
|
@ -27,6 +34,12 @@ export default {
|
||||||
} else {
|
} else {
|
||||||
return 'svg-icon'
|
return 'svg-icon'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
styleExternalIcon() {
|
||||||
|
return {
|
||||||
|
mask: `url(${this.iconClass}) no-repeat 50% 50%`,
|
||||||
|
'-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,4 +53,10 @@ export default {
|
||||||
fill: currentColor;
|
fill: currentColor;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.svg-external-icon {
|
||||||
|
background-color: currentColor;
|
||||||
|
mask-size: cover!important;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -11,7 +11,7 @@ export default {
|
||||||
name: 'AppMain',
|
name: 'AppMain',
|
||||||
computed: {
|
computed: {
|
||||||
key() {
|
key() {
|
||||||
return this.$route.fullPath
|
return this.$route.path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,3 +29,12 @@ export default {
|
||||||
padding-top: 50px;
|
padding-top: 50px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
// fix css style bug in open el-dialog
|
||||||
|
.el-popup-parent--hidden {
|
||||||
|
.fixed-header {
|
||||||
|
padding-right: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -22,8 +22,8 @@
|
||||||
<a target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/#/">
|
<a target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/#/">
|
||||||
<el-dropdown-item>Docs</el-dropdown-item>
|
<el-dropdown-item>Docs</el-dropdown-item>
|
||||||
</a>
|
</a>
|
||||||
<el-dropdown-item divided>
|
<el-dropdown-item divided @click.native="logout">
|
||||||
<span style="display:block;" @click="logout">Log Out</span>
|
<span style="display:block;">Log Out</span>
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
|
|
|
@ -17,8 +17,12 @@ export default {
|
||||||
const vnodes = []
|
const vnodes = []
|
||||||
|
|
||||||
if (icon) {
|
if (icon) {
|
||||||
|
if (icon.includes('el-icon')) {
|
||||||
|
vnodes.push(<i class={[icon, 'sub-el-icon']} />)
|
||||||
|
} else {
|
||||||
vnodes.push(<svg-icon icon-class={icon}/>)
|
vnodes.push(<svg-icon icon-class={icon}/>)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (title) {
|
if (title) {
|
||||||
vnodes.push(<span slot='title'>{(title)}</span>)
|
vnodes.push(<span slot='title'>{(title)}</span>)
|
||||||
|
@ -27,3 +31,11 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.sub-el-icon {
|
||||||
|
color: currentColor;
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<!-- eslint-disable vue/require-component-is -->
|
<component :is="type" v-bind="linkProps(to)">
|
||||||
<component v-bind="linkProps(to)">
|
|
||||||
<slot />
|
<slot />
|
||||||
</component>
|
</component>
|
||||||
</template>
|
</template>
|
||||||
|
@ -16,19 +14,28 @@ export default {
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
isExternal() {
|
||||||
|
return isExternal(this.to)
|
||||||
|
},
|
||||||
|
type() {
|
||||||
|
if (this.isExternal) {
|
||||||
|
return 'a'
|
||||||
|
}
|
||||||
|
return 'router-link'
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
linkProps(url) {
|
linkProps(to) {
|
||||||
if (isExternal(url)) {
|
if (this.isExternal) {
|
||||||
return {
|
return {
|
||||||
is: 'a',
|
href: to,
|
||||||
href: url,
|
|
||||||
target: '_blank',
|
target: '_blank',
|
||||||
rel: 'noopener'
|
rel: 'noopener'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
is: 'router-link',
|
to: to
|
||||||
to: url
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-if="!item.hidden" class="menu-wrapper">
|
<div v-if="!item.hidden">
|
||||||
<template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
|
<template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
|
||||||
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
|
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
|
||||||
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
|
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
|
||||||
|
|
|
@ -44,7 +44,7 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleClickOutside() {
|
handleClickOutside() {
|
||||||
this.$store.dispatch('CloseSideBar', { withoutAnimation: false })
|
this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
src/main.js
14
src/main.js
|
@ -17,15 +17,21 @@ import '@/permission' // permission control
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If you don't want to use mock-server
|
* If you don't want to use mock-server
|
||||||
* you want to use mockjs for request interception
|
* you want to use MockJs for mock api
|
||||||
* you can execute:
|
* you can execute: mockXHR()
|
||||||
*
|
*
|
||||||
* import { mockXHR } from '../mock'
|
* Currently MockJs will be used in the production environment,
|
||||||
* mockXHR()
|
* please remove it before going online ! ! !
|
||||||
*/
|
*/
|
||||||
|
if (process.env.NODE_ENV === 'production') {
|
||||||
|
const { mockXHR } = require('../mock')
|
||||||
|
mockXHR()
|
||||||
|
}
|
||||||
|
|
||||||
// set ElementUI lang to EN
|
// set ElementUI lang to EN
|
||||||
Vue.use(ElementUI, { locale })
|
Vue.use(ElementUI, { locale })
|
||||||
|
// 如果想要中文版 element-ui,按如下方式声明
|
||||||
|
// Vue.use(ElementUI)
|
||||||
|
|
||||||
Vue.config.productionTip = false
|
Vue.config.productionTip = false
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ import Layout from '@/layout'
|
||||||
* meta : {
|
* meta : {
|
||||||
roles: ['admin','editor'] control the page roles (you can set multiple roles)
|
roles: ['admin','editor'] control the page roles (you can set multiple roles)
|
||||||
title: 'title' the name show in sidebar and breadcrumb (recommend set)
|
title: 'title' the name show in sidebar and breadcrumb (recommend set)
|
||||||
icon: 'svg-name' the icon show in the sidebar
|
icon: 'svg-name'/'el-icon-x' the icon show in the sidebar
|
||||||
breadcrumb: false if set false, the item will hidden in breadcrumb(default is true)
|
breadcrumb: false if set false, the item will hidden in breadcrumb(default is true)
|
||||||
activeMenu: '/example/list' if set path, the sidebar will highlight the path you set
|
activeMenu: '/example/list' if set path, the sidebar will highlight the path you set
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ export const constantRoutes = [
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/example/table',
|
redirect: '/example/table',
|
||||||
name: 'Example',
|
name: 'Example',
|
||||||
meta: { title: 'Example', icon: 'example' },
|
meta: { title: 'Example', icon: 'el-icon-s-help' },
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: 'table',
|
path: 'table',
|
||||||
|
@ -143,6 +143,7 @@ export const constantRoutes = [
|
||||||
{
|
{
|
||||||
path: 'menu2',
|
path: 'menu2',
|
||||||
component: () => import('@/views/nested/menu2/index'),
|
component: () => import('@/views/nested/menu2/index'),
|
||||||
|
name: 'Menu2',
|
||||||
meta: { title: 'menu2' }
|
meta: { title: 'menu2' }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -10,6 +10,7 @@ const state = {
|
||||||
|
|
||||||
const mutations = {
|
const mutations = {
|
||||||
CHANGE_SETTING: (state, { key, value }) => {
|
CHANGE_SETTING: (state, { key, value }) => {
|
||||||
|
// eslint-disable-next-line no-prototype-builtins
|
||||||
if (state.hasOwnProperty(key)) {
|
if (state.hasOwnProperty(key)) {
|
||||||
state[key] = value
|
state[key] = value
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,20 @@ import { login, logout, getInfo } from '@/api/user'
|
||||||
import { getToken, setToken, removeToken } from '@/utils/auth'
|
import { getToken, setToken, removeToken } from '@/utils/auth'
|
||||||
import { resetRouter } from '@/router'
|
import { resetRouter } from '@/router'
|
||||||
|
|
||||||
const state = {
|
const getDefaultState = () => {
|
||||||
|
return {
|
||||||
token: getToken(),
|
token: getToken(),
|
||||||
name: '',
|
name: '',
|
||||||
avatar: ''
|
avatar: ''
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const state = getDefaultState()
|
||||||
|
|
||||||
const mutations = {
|
const mutations = {
|
||||||
|
RESET_STATE: (state) => {
|
||||||
|
Object.assign(state, getDefaultState())
|
||||||
|
},
|
||||||
SET_TOKEN: (state, token) => {
|
SET_TOKEN: (state, token) => {
|
||||||
state.token = token
|
state.token = token
|
||||||
},
|
},
|
||||||
|
@ -43,7 +50,7 @@ const actions = {
|
||||||
const { data } = response
|
const { data } = response
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
reject('Verification failed, please Login again.')
|
return reject('Verification failed, please Login again.')
|
||||||
}
|
}
|
||||||
|
|
||||||
const { name, avatar } = data
|
const { name, avatar } = data
|
||||||
|
@ -61,9 +68,9 @@ const actions = {
|
||||||
logout({ commit, state }) {
|
logout({ commit, state }) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
logout(state.token).then(() => {
|
logout(state.token).then(() => {
|
||||||
commit('SET_TOKEN', '')
|
removeToken() // must remove token first
|
||||||
removeToken()
|
|
||||||
resetRouter()
|
resetRouter()
|
||||||
|
commit('RESET_STATE')
|
||||||
resolve()
|
resolve()
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
reject(error)
|
reject(error)
|
||||||
|
@ -74,8 +81,8 @@ const actions = {
|
||||||
// remove token
|
// remove token
|
||||||
resetToken({ commit }) {
|
resetToken({ commit }) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
commit('SET_TOKEN', '')
|
removeToken() // must remove token first
|
||||||
removeToken()
|
commit('RESET_STATE')
|
||||||
resolve()
|
resolve()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,3 +42,8 @@
|
||||||
display: block
|
display: block
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// to fix el-date-picker css style
|
||||||
|
.el-range-separator {
|
||||||
|
box-sizing: content-box;
|
||||||
|
}
|
||||||
|
|
|
@ -57,6 +57,11 @@
|
||||||
margin-right: 16px;
|
margin-right: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sub-el-icon {
|
||||||
|
margin-right: 12px;
|
||||||
|
margin-left: -2px;
|
||||||
|
}
|
||||||
|
|
||||||
.el-menu {
|
.el-menu {
|
||||||
border: none;
|
border: none;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -95,10 +100,6 @@
|
||||||
margin-left: 54px;
|
margin-left: 54px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.svg-icon {
|
|
||||||
margin-right: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.submenu-title-noDropdown {
|
.submenu-title-noDropdown {
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -109,6 +110,10 @@
|
||||||
.svg-icon {
|
.svg-icon {
|
||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sub-el-icon {
|
||||||
|
margin-left: 19px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,6 +127,10 @@
|
||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sub-el-icon {
|
||||||
|
margin-left: 19px;
|
||||||
|
}
|
||||||
|
|
||||||
.el-submenu__icon-arrow {
|
.el-submenu__icon-arrow {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
@ -182,6 +191,10 @@
|
||||||
.svg-icon {
|
.svg-icon {
|
||||||
margin-right: 16px;
|
margin-right: 16px;
|
||||||
}
|
}
|
||||||
|
.sub-el-icon {
|
||||||
|
margin-right: 12px;
|
||||||
|
margin-left: -2px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.nest-menu .el-submenu>.el-submenu__title,
|
.nest-menu .el-submenu>.el-submenu__title,
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
* Parse the time to string
|
* Parse the time to string
|
||||||
* @param {(Object|string|number)} time
|
* @param {(Object|string|number)} time
|
||||||
* @param {string} cFormat
|
* @param {string} cFormat
|
||||||
* @returns {string}
|
* @returns {string | null}
|
||||||
*/
|
*/
|
||||||
export function parseTime(time, cFormat) {
|
export function parseTime(time, cFormat) {
|
||||||
if (arguments.length === 0) {
|
if (arguments.length === 0 || !time) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
|
const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
|
||||||
|
@ -17,9 +17,17 @@ export function parseTime(time, cFormat) {
|
||||||
if (typeof time === 'object') {
|
if (typeof time === 'object') {
|
||||||
date = time
|
date = time
|
||||||
} else {
|
} else {
|
||||||
if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
|
if ((typeof time === 'string')) {
|
||||||
|
if ((/^[0-9]+$/.test(time))) {
|
||||||
|
// support "1548221490638"
|
||||||
time = parseInt(time)
|
time = parseInt(time)
|
||||||
|
} else {
|
||||||
|
// support safari
|
||||||
|
// https://stackoverflow.com/questions/4310953/invalid-date-in-safari
|
||||||
|
time = time.replace(new RegExp(/-/gm), '/')
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((typeof time === 'number') && (time.toString().length === 10)) {
|
if ((typeof time === 'number') && (time.toString().length === 10)) {
|
||||||
time = time * 1000
|
time = time * 1000
|
||||||
}
|
}
|
||||||
|
@ -34,14 +42,11 @@ export function parseTime(time, cFormat) {
|
||||||
s: date.getSeconds(),
|
s: date.getSeconds(),
|
||||||
a: date.getDay()
|
a: date.getDay()
|
||||||
}
|
}
|
||||||
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
|
const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
|
||||||
let value = formatObj[key]
|
const value = formatObj[key]
|
||||||
// Note: getDay() returns 0 on Sunday
|
// Note: getDay() returns 0 on Sunday
|
||||||
if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] }
|
if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] }
|
||||||
if (result.length > 0 && value < 10) {
|
return value.toString().padStart(2, '0')
|
||||||
value = '0' + value
|
|
||||||
}
|
|
||||||
return value || 0
|
|
||||||
})
|
})
|
||||||
return time_str
|
return time_str
|
||||||
}
|
}
|
||||||
|
@ -94,17 +99,19 @@ export function formatTime(time, option) {
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
export function param2Obj(url) {
|
export function param2Obj(url) {
|
||||||
const search = url.split('?')[1]
|
const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
|
||||||
if (!search) {
|
if (!search) {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
return JSON.parse(
|
const obj = {}
|
||||||
'{"' +
|
const searchArr = search.split('&')
|
||||||
decodeURIComponent(search)
|
searchArr.forEach(v => {
|
||||||
.replace(/"/g, '\\"')
|
const index = v.indexOf('=')
|
||||||
.replace(/&/g, '","')
|
if (index !== -1) {
|
||||||
.replace(/=/g, '":"')
|
const name = v.substring(0, index)
|
||||||
.replace(/\+/g, ' ') +
|
const val = v.substring(index + 1, v.length)
|
||||||
'"}'
|
obj[name] = val
|
||||||
)
|
}
|
||||||
|
})
|
||||||
|
return obj
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { getToken } from '@/utils/auth'
|
||||||
// create an axios instance
|
// create an axios instance
|
||||||
const service = axios.create({
|
const service = axios.create({
|
||||||
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
|
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
|
||||||
withCredentials: true, // send cookies when cross-domain requests
|
// withCredentials: true, // send cookies when cross-domain requests
|
||||||
timeout: 5000 // request timeout
|
timeout: 5000 // request timeout
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ service.interceptors.response.use(
|
||||||
// if the custom code is not 20000, it is judged as an error.
|
// if the custom code is not 20000, it is judged as an error.
|
||||||
if (res.code !== 20000) {
|
if (res.code !== 20000) {
|
||||||
Message({
|
Message({
|
||||||
message: res.message || 'error',
|
message: res.message || 'Error',
|
||||||
type: 'error',
|
type: 'error',
|
||||||
duration: 5 * 1000
|
duration: 5 * 1000
|
||||||
})
|
})
|
||||||
|
@ -66,7 +66,7 @@ service.interceptors.response.use(
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return Promise.reject(res.message || 'error')
|
return Promise.reject(new Error(res.message || 'Error'))
|
||||||
} else {
|
} else {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { param2Obj } from '@/utils/index.js'
|
||||||
|
describe('Utils:param2Obj', () => {
|
||||||
|
const url = 'https://github.com/PanJiaChen/vue-element-admin?name=bill&age=29&sex=1&field=dGVzdA==&key=%E6%B5%8B%E8%AF%95'
|
||||||
|
|
||||||
|
it('param2Obj test', () => {
|
||||||
|
expect(param2Obj(url)).toEqual({
|
||||||
|
name: 'bill',
|
||||||
|
age: '29',
|
||||||
|
sex: '1',
|
||||||
|
field: window.btoa('test'),
|
||||||
|
key: '测试'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
|
@ -5,6 +5,9 @@ describe('Utils:parseTime', () => {
|
||||||
it('timestamp', () => {
|
it('timestamp', () => {
|
||||||
expect(parseTime(d)).toBe('2018-07-13 17:54:01')
|
expect(parseTime(d)).toBe('2018-07-13 17:54:01')
|
||||||
})
|
})
|
||||||
|
it('timestamp string', () => {
|
||||||
|
expect(parseTime((d + ''))).toBe('2018-07-13 17:54:01')
|
||||||
|
})
|
||||||
it('ten digits timestamp', () => {
|
it('ten digits timestamp', () => {
|
||||||
expect(parseTime((d / 1000).toFixed(0))).toBe('2018-07-13 17:54:01')
|
expect(parseTime((d / 1000).toFixed(0))).toBe('2018-07-13 17:54:01')
|
||||||
})
|
})
|
||||||
|
@ -25,4 +28,8 @@ describe('Utils:parseTime', () => {
|
||||||
it('empty argument', () => {
|
it('empty argument', () => {
|
||||||
expect(parseTime()).toBeNull()
|
expect(parseTime()).toBeNull()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('null', () => {
|
||||||
|
expect(parseTime(null)).toBeNull()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -7,7 +7,13 @@ function resolve(dir) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const name = defaultSettings.title || 'vue Admin Template' // page title
|
const name = defaultSettings.title || 'vue Admin Template' // page title
|
||||||
const port = 9528 // dev port
|
|
||||||
|
// If your port is set to 80,
|
||||||
|
// use administrator privileges to execute the command line.
|
||||||
|
// For example, Mac: sudo npm run
|
||||||
|
// You can change the port by the following methods:
|
||||||
|
// port = 9528 npm run dev OR npm run dev --port = 9528
|
||||||
|
const port = process.env.port || process.env.npm_config_port || 9528 // dev port
|
||||||
|
|
||||||
// All configuration item explanations can be find in https://cli.vuejs.org/config/
|
// All configuration item explanations can be find in https://cli.vuejs.org/config/
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
@ -30,18 +36,7 @@ module.exports = {
|
||||||
warnings: false,
|
warnings: false,
|
||||||
errors: true
|
errors: true
|
||||||
},
|
},
|
||||||
proxy: {
|
before: require('./mock/mock-server.js')
|
||||||
// change xxx-api/login => mock/login
|
|
||||||
// detail: https://cli.vuejs.org/config/#devserver-proxy
|
|
||||||
[process.env.VUE_APP_BASE_API]: {
|
|
||||||
target: `http://localhost:${port}/mock`,
|
|
||||||
changeOrigin: true,
|
|
||||||
pathRewrite: {
|
|
||||||
['^' + process.env.VUE_APP_BASE_API]: ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
after: require('./mock/mock-server.js')
|
|
||||||
},
|
},
|
||||||
configureWebpack: {
|
configureWebpack: {
|
||||||
// provide the app's title in webpack's name field, so that
|
// provide the app's title in webpack's name field, so that
|
||||||
|
@ -54,8 +49,19 @@ module.exports = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
chainWebpack(config) {
|
chainWebpack(config) {
|
||||||
config.plugins.delete('preload') // TODO: need test
|
// it can improve the speed of the first screen, it is recommended to turn on preload
|
||||||
config.plugins.delete('prefetch') // TODO: need test
|
config.plugin('preload').tap(() => [
|
||||||
|
{
|
||||||
|
rel: 'preload',
|
||||||
|
// to ignore runtime.js
|
||||||
|
// https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/cli-service/lib/config/app.js#L171
|
||||||
|
fileBlacklist: [/\.map$/, /hot-update\.js$/, /runtime\..*\.js$/],
|
||||||
|
include: 'initial'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
// when there are many pages, it will cause too many meaningless requests
|
||||||
|
config.plugins.delete('prefetch')
|
||||||
|
|
||||||
// set svg-sprite-loader
|
// set svg-sprite-loader
|
||||||
config.module
|
config.module
|
||||||
|
@ -74,23 +80,6 @@ module.exports = {
|
||||||
})
|
})
|
||||||
.end()
|
.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
|
config
|
||||||
.when(process.env.NODE_ENV !== 'development',
|
.when(process.env.NODE_ENV !== 'development',
|
||||||
config => {
|
config => {
|
||||||
|
@ -126,6 +115,7 @@ module.exports = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
// https:// webpack.js.org/configuration/optimization/#optimizationruntimechunk
|
||||||
config.optimization.runtimeChunk('single')
|
config.optimization.runtimeChunk('single')
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue