first commit
|
@ -1,6 +0,0 @@
|
||||||
[*.{js,jsx,ts,tsx,vue}]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
insert_final_newline = true
|
|
||||||
max_line_length = 150
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
# just a flag
|
||||||
|
ENV = 'development'
|
||||||
|
|
||||||
|
# base api
|
||||||
|
VUE_APP_BASE_API = '/dev-api'
|
|
@ -1,2 +1,6 @@
|
||||||
# 发布
|
# just a flag
|
||||||
NODE_ENV=production
|
ENV = 'production'
|
||||||
|
|
||||||
|
# base api
|
||||||
|
VUE_APP_BASE_API = '/prod-api'
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
NODE_ENV = production
|
||||||
|
|
||||||
|
# just a flag
|
||||||
|
ENV = 'staging'
|
||||||
|
|
||||||
|
# base api
|
||||||
|
VUE_APP_BASE_API = '/stage-api'
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
build/*.js
|
||||||
|
src/assets
|
||||||
|
public
|
||||||
|
dist
|
|
@ -0,0 +1,198 @@
|
||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
parserOptions: {
|
||||||
|
parser: 'babel-eslint',
|
||||||
|
sourceType: 'module'
|
||||||
|
},
|
||||||
|
env: {
|
||||||
|
browser: true,
|
||||||
|
node: true,
|
||||||
|
es6: true,
|
||||||
|
},
|
||||||
|
extends: ['plugin:vue/recommended', 'eslint:recommended'],
|
||||||
|
|
||||||
|
// add your custom rules here
|
||||||
|
//it is base on https://github.com/vuejs/eslint-config-vue
|
||||||
|
rules: {
|
||||||
|
"vue/max-attributes-per-line": [2, {
|
||||||
|
"singleline": 10,
|
||||||
|
"multiline": {
|
||||||
|
"max": 1,
|
||||||
|
"allowFirstLine": false
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
"vue/singleline-html-element-content-newline": "off",
|
||||||
|
"vue/multiline-html-element-content-newline":"off",
|
||||||
|
"vue/name-property-casing": ["error", "PascalCase"],
|
||||||
|
"vue/no-v-html": "off",
|
||||||
|
'accessor-pairs': 2,
|
||||||
|
'arrow-spacing': [2, {
|
||||||
|
'before': true,
|
||||||
|
'after': true
|
||||||
|
}],
|
||||||
|
'block-spacing': [2, 'always'],
|
||||||
|
'brace-style': [2, '1tbs', {
|
||||||
|
'allowSingleLine': true
|
||||||
|
}],
|
||||||
|
'camelcase': [0, {
|
||||||
|
'properties': 'always'
|
||||||
|
}],
|
||||||
|
'comma-dangle': [2, 'never'],
|
||||||
|
'comma-spacing': [2, {
|
||||||
|
'before': false,
|
||||||
|
'after': true
|
||||||
|
}],
|
||||||
|
'comma-style': [2, 'last'],
|
||||||
|
'constructor-super': 2,
|
||||||
|
'curly': [2, 'multi-line'],
|
||||||
|
'dot-location': [2, 'property'],
|
||||||
|
'eol-last': 2,
|
||||||
|
'eqeqeq': ["error", "always", {"null": "ignore"}],
|
||||||
|
'generator-star-spacing': [2, {
|
||||||
|
'before': true,
|
||||||
|
'after': true
|
||||||
|
}],
|
||||||
|
'handle-callback-err': [2, '^(err|error)$'],
|
||||||
|
'indent': [2, 2, {
|
||||||
|
'SwitchCase': 1
|
||||||
|
}],
|
||||||
|
'jsx-quotes': [2, 'prefer-single'],
|
||||||
|
'key-spacing': [2, {
|
||||||
|
'beforeColon': false,
|
||||||
|
'afterColon': true
|
||||||
|
}],
|
||||||
|
'keyword-spacing': [2, {
|
||||||
|
'before': true,
|
||||||
|
'after': true
|
||||||
|
}],
|
||||||
|
'new-cap': [2, {
|
||||||
|
'newIsCap': true,
|
||||||
|
'capIsNew': false
|
||||||
|
}],
|
||||||
|
'new-parens': 2,
|
||||||
|
'no-array-constructor': 2,
|
||||||
|
'no-caller': 2,
|
||||||
|
'no-console': 'off',
|
||||||
|
'no-class-assign': 2,
|
||||||
|
'no-cond-assign': 2,
|
||||||
|
'no-const-assign': 2,
|
||||||
|
'no-control-regex': 0,
|
||||||
|
'no-delete-var': 2,
|
||||||
|
'no-dupe-args': 2,
|
||||||
|
'no-dupe-class-members': 2,
|
||||||
|
'no-dupe-keys': 2,
|
||||||
|
'no-duplicate-case': 2,
|
||||||
|
'no-empty-character-class': 2,
|
||||||
|
'no-empty-pattern': 2,
|
||||||
|
'no-eval': 2,
|
||||||
|
'no-ex-assign': 2,
|
||||||
|
'no-extend-native': 2,
|
||||||
|
'no-extra-bind': 2,
|
||||||
|
'no-extra-boolean-cast': 2,
|
||||||
|
'no-extra-parens': [2, 'functions'],
|
||||||
|
'no-fallthrough': 2,
|
||||||
|
'no-floating-decimal': 2,
|
||||||
|
'no-func-assign': 2,
|
||||||
|
'no-implied-eval': 2,
|
||||||
|
'no-inner-declarations': [2, 'functions'],
|
||||||
|
'no-invalid-regexp': 2,
|
||||||
|
'no-irregular-whitespace': 2,
|
||||||
|
'no-iterator': 2,
|
||||||
|
'no-label-var': 2,
|
||||||
|
'no-labels': [2, {
|
||||||
|
'allowLoop': false,
|
||||||
|
'allowSwitch': false
|
||||||
|
}],
|
||||||
|
'no-lone-blocks': 2,
|
||||||
|
'no-mixed-spaces-and-tabs': 2,
|
||||||
|
'no-multi-spaces': 2,
|
||||||
|
'no-multi-str': 2,
|
||||||
|
'no-multiple-empty-lines': [2, {
|
||||||
|
'max': 1
|
||||||
|
}],
|
||||||
|
'no-native-reassign': 2,
|
||||||
|
'no-negated-in-lhs': 2,
|
||||||
|
'no-new-object': 2,
|
||||||
|
'no-new-require': 2,
|
||||||
|
'no-new-symbol': 2,
|
||||||
|
'no-new-wrappers': 2,
|
||||||
|
'no-obj-calls': 2,
|
||||||
|
'no-octal': 2,
|
||||||
|
'no-octal-escape': 2,
|
||||||
|
'no-path-concat': 2,
|
||||||
|
'no-proto': 2,
|
||||||
|
'no-redeclare': 2,
|
||||||
|
'no-regex-spaces': 2,
|
||||||
|
'no-return-assign': [2, 'except-parens'],
|
||||||
|
'no-self-assign': 2,
|
||||||
|
'no-self-compare': 2,
|
||||||
|
'no-sequences': 2,
|
||||||
|
'no-shadow-restricted-names': 2,
|
||||||
|
'no-spaced-func': 2,
|
||||||
|
'no-sparse-arrays': 2,
|
||||||
|
'no-this-before-super': 2,
|
||||||
|
'no-throw-literal': 2,
|
||||||
|
'no-trailing-spaces': 2,
|
||||||
|
'no-undef': 2,
|
||||||
|
'no-undef-init': 2,
|
||||||
|
'no-unexpected-multiline': 2,
|
||||||
|
'no-unmodified-loop-condition': 2,
|
||||||
|
'no-unneeded-ternary': [2, {
|
||||||
|
'defaultAssignment': false
|
||||||
|
}],
|
||||||
|
'no-unreachable': 2,
|
||||||
|
'no-unsafe-finally': 2,
|
||||||
|
'no-unused-vars': [2, {
|
||||||
|
'vars': 'all',
|
||||||
|
'args': 'none'
|
||||||
|
}],
|
||||||
|
'no-useless-call': 2,
|
||||||
|
'no-useless-computed-key': 2,
|
||||||
|
'no-useless-constructor': 2,
|
||||||
|
'no-useless-escape': 0,
|
||||||
|
'no-whitespace-before-property': 2,
|
||||||
|
'no-with': 2,
|
||||||
|
'one-var': [2, {
|
||||||
|
'initialized': 'never'
|
||||||
|
}],
|
||||||
|
'operator-linebreak': [2, 'after', {
|
||||||
|
'overrides': {
|
||||||
|
'?': 'before',
|
||||||
|
':': 'before'
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
'padded-blocks': [2, 'never'],
|
||||||
|
'quotes': [2, 'single', {
|
||||||
|
'avoidEscape': true,
|
||||||
|
'allowTemplateLiterals': true
|
||||||
|
}],
|
||||||
|
'semi': [2, 'never'],
|
||||||
|
'semi-spacing': [2, {
|
||||||
|
'before': false,
|
||||||
|
'after': true
|
||||||
|
}],
|
||||||
|
'space-before-blocks': [2, 'always'],
|
||||||
|
'space-before-function-paren': [2, 'never'],
|
||||||
|
'space-in-parens': [2, 'never'],
|
||||||
|
'space-infix-ops': 2,
|
||||||
|
'space-unary-ops': [2, {
|
||||||
|
'words': true,
|
||||||
|
'nonwords': false
|
||||||
|
}],
|
||||||
|
'spaced-comment': [2, 'always', {
|
||||||
|
'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
|
||||||
|
}],
|
||||||
|
'template-curly-spacing': [2, 'never'],
|
||||||
|
'use-isnan': 2,
|
||||||
|
'valid-typeof': 2,
|
||||||
|
'wrap-iife': [2, 'any'],
|
||||||
|
'yield-star-spacing': [2, 'both'],
|
||||||
|
'yoda': [2, 'never'],
|
||||||
|
'prefer-const': 2,
|
||||||
|
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
|
||||||
|
'object-curly-spacing': [2, 'always', {
|
||||||
|
objectsInObjects: false
|
||||||
|
}],
|
||||||
|
'array-bracket-spacing': [2, 'never']
|
||||||
|
}
|
||||||
|
}
|
55
README.md
|
@ -1,4 +1,4 @@
|
||||||
# jointcloud 云际计算
|
# kubeX
|
||||||
|
|
||||||
## 电脑需要安装 node 环境
|
## 电脑需要安装 node 环境
|
||||||
|
|
||||||
|
@ -20,37 +20,26 @@ npm run dev
|
||||||
npm run build
|
npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
### 项目目录结构 src
|
```bash
|
||||||
|
# build for test environment
|
||||||
|
npm run build:stage
|
||||||
|
|
||||||
├── api `接口`
|
# build for production environment
|
||||||
├── assets `图片资源`
|
npm run build:prod
|
||||||
│ ├── modules `八大模块图片`
|
```
|
||||||
│ ├── partner `合作伙伴图片`
|
|
||||||
├── components `组件`
|
|
||||||
│ ├── documents `文件`
|
|
||||||
│ ├── modules `模块组件`
|
|
||||||
│ │ ├── cloudBookkeepingAsync `云际异步记账`
|
|
||||||
│ │ ├── cloudBookkeepingSync `云际同步记账`
|
|
||||||
│ │ ├── cloudComputation `云际计算`
|
|
||||||
│ │ ├── cloudStorage `云际存储`
|
|
||||||
│ │ ├── disasterRecovery `云际容灾`
|
|
||||||
│ │ ├── serviceRecommendation `云际推荐`
|
|
||||||
│ │ └── header.vue `模块公共头部`
|
|
||||||
│ └── .. `其他组件`
|
|
||||||
├── mixin `复用代码`
|
|
||||||
├── router `路径声明`
|
|
||||||
├── scripts/map `列表map(表头)`
|
|
||||||
├── store `vuex存储`
|
|
||||||
├── styles `公共样式文件`
|
|
||||||
├── utils `封装请求及多语言`
|
|
||||||
├── views `page页面`
|
|
||||||
│ ├── error-page `模块页面`
|
|
||||||
│ ├── modules `模块页面`
|
|
||||||
│ │ ├── cloudBookkeepingAsync `云际异步记账`
|
|
||||||
│ │ ├── cloudBookkeepingSync `云际同步记账`
|
|
||||||
│ │ ├── cloudComputation `云际计算`
|
|
||||||
│ │ ├── cloudStorage `云际存储`
|
|
||||||
│ │ ├── disasterRecovery `云际容灾`
|
|
||||||
│ │ └── serviceRecommendation `云际推荐`
|
|
||||||
└── └── .. `其他页面`
|
|
||||||
|
|
||||||
|
## Advanced
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# preview the release environment effect
|
||||||
|
npm run preview
|
||||||
|
|
||||||
|
# preview the release environment effect + static resource analysis
|
||||||
|
npm run preview -- --report
|
||||||
|
|
||||||
|
# code format check
|
||||||
|
npm run lint
|
||||||
|
|
||||||
|
# code format check and auto fix
|
||||||
|
npm run lint -- --fix
|
||||||
|
```
|
||||||
|
|
|
@ -1,5 +1,14 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
presets: [
|
presets: [
|
||||||
'@vue/cli-plugin-babel/preset',
|
// 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,35 @@
|
||||||
|
const { run } = require('runjs')
|
||||||
|
const chalk = require('chalk')
|
||||||
|
const config = require('../vue.config.js')
|
||||||
|
const rawArgv = process.argv.slice(2)
|
||||||
|
const args = rawArgv.join(' ')
|
||||||
|
|
||||||
|
if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
|
||||||
|
const report = rawArgv.includes('--report')
|
||||||
|
|
||||||
|
run(`vue-cli-service build ${args}`)
|
||||||
|
|
||||||
|
const port = 9526
|
||||||
|
const publicPath = config.publicPath
|
||||||
|
|
||||||
|
var connect = require('connect')
|
||||||
|
var serveStatic = require('serve-static')
|
||||||
|
const app = connect()
|
||||||
|
|
||||||
|
app.use(
|
||||||
|
publicPath,
|
||||||
|
serveStatic('./dist', {
|
||||||
|
index: ['index.html', '/']
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
app.listen(port, function () {
|
||||||
|
console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`))
|
||||||
|
if (report) {
|
||||||
|
console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`))
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
run(`vue-cli-service build ${args}`)
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
module.exports = {
|
||||||
|
moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
|
||||||
|
transform: {
|
||||||
|
'^.+\\.vue$': 'vue-jest',
|
||||||
|
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
|
||||||
|
'jest-transform-stub',
|
||||||
|
'^.+\\.jsx?$': 'babel-jest'
|
||||||
|
},
|
||||||
|
moduleNameMapper: {
|
||||||
|
'^@/(.*)$': '<rootDir>/src/$1'
|
||||||
|
},
|
||||||
|
snapshotSerializers: ['jest-serializer-vue'],
|
||||||
|
testMatch: [
|
||||||
|
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
|
||||||
|
],
|
||||||
|
collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'],
|
||||||
|
coverageDirectory: '<rootDir>/tests/unit/coverage',
|
||||||
|
// 'collectCoverage': true,
|
||||||
|
'coverageReporters': [
|
||||||
|
'lcov',
|
||||||
|
'text-summary'
|
||||||
|
],
|
||||||
|
testURL: 'http://localhost/'
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "./",
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["src/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"exclude": ["node_modules", "dist"]
|
||||||
|
}
|
|
@ -0,0 +1,116 @@
|
||||||
|
const Mock = require('mockjs')
|
||||||
|
|
||||||
|
const List = []
|
||||||
|
const count = 100
|
||||||
|
|
||||||
|
const baseContent = '<p>I am testing data, I am testing data.</p><p><img src="https://wpimg.wallstcn.com/4c69009c-0fd4-4153-b112-6cb53d1cf943"></p>'
|
||||||
|
const image_uri = 'https://wpimg.wallstcn.com/e4558086-631c-425c-9430-56ffb46e70b3'
|
||||||
|
|
||||||
|
for (let i = 0; i < count; i++) {
|
||||||
|
List.push(Mock.mock({
|
||||||
|
id: '@increment',
|
||||||
|
timestamp: +Mock.Random.date('T'),
|
||||||
|
author: '@first',
|
||||||
|
reviewer: '@first',
|
||||||
|
title: '@title(5, 10)',
|
||||||
|
content_short: 'mock data',
|
||||||
|
content: baseContent,
|
||||||
|
forecast: '@float(0, 100, 2, 2)',
|
||||||
|
importance: '@integer(1, 3)',
|
||||||
|
'type|1': ['CN', 'US', 'JP', 'EU'],
|
||||||
|
'status|1': ['published', 'draft'],
|
||||||
|
display_time: '@datetime',
|
||||||
|
comment_disabled: true,
|
||||||
|
pageviews: '@integer(300, 5000)',
|
||||||
|
image_uri,
|
||||||
|
platforms: ['a-platform']
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = [
|
||||||
|
{
|
||||||
|
url: '/vue-element-admin/article/list',
|
||||||
|
type: 'get',
|
||||||
|
response: config => {
|
||||||
|
const { importance, type, title, page = 1, limit = 20, sort } = config.query
|
||||||
|
|
||||||
|
let mockList = List.filter(item => {
|
||||||
|
if (importance && item.importance !== +importance) return false
|
||||||
|
if (type && item.type !== type) return false
|
||||||
|
if (title && item.title.indexOf(title) < 0) return false
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
if (sort === '-id') {
|
||||||
|
mockList = mockList.reverse()
|
||||||
|
}
|
||||||
|
|
||||||
|
const pageList = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1))
|
||||||
|
|
||||||
|
return {
|
||||||
|
code: 20000,
|
||||||
|
data: {
|
||||||
|
total: mockList.length,
|
||||||
|
items: pageList
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
url: '/vue-element-admin/article/detail',
|
||||||
|
type: 'get',
|
||||||
|
response: config => {
|
||||||
|
const { id } = config.query
|
||||||
|
for (const article of List) {
|
||||||
|
if (article.id === +id) {
|
||||||
|
return {
|
||||||
|
code: 20000,
|
||||||
|
data: article
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
url: '/vue-element-admin/article/pv',
|
||||||
|
type: 'get',
|
||||||
|
response: _ => {
|
||||||
|
return {
|
||||||
|
code: 20000,
|
||||||
|
data: {
|
||||||
|
pvData: [
|
||||||
|
{ key: 'PC', pv: 1024 },
|
||||||
|
{ key: 'mobile', pv: 1024 },
|
||||||
|
{ key: 'ios', pv: 1024 },
|
||||||
|
{ key: 'android', pv: 1024 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
url: '/vue-element-admin/article/create',
|
||||||
|
type: 'post',
|
||||||
|
response: _ => {
|
||||||
|
return {
|
||||||
|
code: 20000,
|
||||||
|
data: 'success'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
url: '/vue-element-admin/article/update',
|
||||||
|
type: 'post',
|
||||||
|
response: _ => {
|
||||||
|
return {
|
||||||
|
code: 20000,
|
||||||
|
data: 'success'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
const Mock = require('mockjs')
|
||||||
|
const { param2Obj } = require('./utils')
|
||||||
|
|
||||||
|
const user = require('./user')
|
||||||
|
const role = require('./role')
|
||||||
|
const article = require('./article')
|
||||||
|
const search = require('./remote-search')
|
||||||
|
|
||||||
|
const mocks = [
|
||||||
|
...user,
|
||||||
|
...role,
|
||||||
|
...article,
|
||||||
|
...search
|
||||||
|
]
|
||||||
|
|
||||||
|
// for front mock
|
||||||
|
// please use it cautiously, it will redefine XMLHttpRequest,
|
||||||
|
// which will cause many of your third-party libraries to be invalidated(like progress event).
|
||||||
|
function mockXHR() {
|
||||||
|
// mock patch
|
||||||
|
// https://github.com/nuysoft/Mock/issues/300
|
||||||
|
Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
|
||||||
|
Mock.XHR.prototype.send = function() {
|
||||||
|
if (this.custom.xhr) {
|
||||||
|
this.custom.xhr.withCredentials = this.withCredentials || false
|
||||||
|
|
||||||
|
if (this.responseType) {
|
||||||
|
this.custom.xhr.responseType = this.responseType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.proxy_send(...arguments)
|
||||||
|
}
|
||||||
|
|
||||||
|
function XHR2ExpressReqWrap(respond) {
|
||||||
|
return function(options) {
|
||||||
|
let result = null
|
||||||
|
if (respond instanceof Function) {
|
||||||
|
const { body, type, url } = options
|
||||||
|
// https://expressjs.com/en/4x/api.html#req
|
||||||
|
result = respond({
|
||||||
|
method: type,
|
||||||
|
body: JSON.parse(body),
|
||||||
|
query: param2Obj(url)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
result = respond
|
||||||
|
}
|
||||||
|
return Mock.mock(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const i of mocks) {
|
||||||
|
Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
mocks,
|
||||||
|
mockXHR
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
const chokidar = require('chokidar')
|
||||||
|
const bodyParser = require('body-parser')
|
||||||
|
const chalk = require('chalk')
|
||||||
|
const path = require('path')
|
||||||
|
const Mock = require('mockjs')
|
||||||
|
|
||||||
|
const mockDir = path.join(process.cwd(), 'mock')
|
||||||
|
|
||||||
|
function registerRoutes(app) {
|
||||||
|
let mockLastIndex
|
||||||
|
const { mocks } = require('./index.js')
|
||||||
|
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)
|
||||||
|
mockLastIndex = app._router.stack.length
|
||||||
|
}
|
||||||
|
const mockRoutesLength = Object.keys(mocksForServer).length
|
||||||
|
return {
|
||||||
|
mockRoutesLength: mockRoutesLength,
|
||||||
|
mockStartIndex: mockLastIndex - mockRoutesLength
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function unregisterRoutes() {
|
||||||
|
Object.keys(require.cache).forEach(i => {
|
||||||
|
if (i.includes(mockDir)) {
|
||||||
|
delete require.cache[require.resolve(i)]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// for mock server
|
||||||
|
const responseFake = (url, type, respond) => {
|
||||||
|
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
|
||||||
|
// https://expressjs.com/en/4x/api.html#req.body
|
||||||
|
app.use(bodyParser.json())
|
||||||
|
app.use(bodyParser.urlencoded({
|
||||||
|
extended: true
|
||||||
|
}))
|
||||||
|
|
||||||
|
const mockRoutes = registerRoutes(app)
|
||||||
|
var mockRoutesLength = mockRoutes.mockRoutesLength
|
||||||
|
var mockStartIndex = mockRoutes.mockStartIndex
|
||||||
|
|
||||||
|
// watch files, hot reload mock server
|
||||||
|
chokidar.watch(mockDir, {
|
||||||
|
ignored: /mock-server/,
|
||||||
|
ignoreInitial: true
|
||||||
|
}).on('all', (event, path) => {
|
||||||
|
if (event === 'change' || event === 'add') {
|
||||||
|
try {
|
||||||
|
// remove mock routes stack
|
||||||
|
app._router.stack.splice(mockStartIndex, mockRoutesLength)
|
||||||
|
|
||||||
|
// clear routes cache
|
||||||
|
unregisterRoutes()
|
||||||
|
|
||||||
|
const mockRoutes = registerRoutes(app)
|
||||||
|
mockRoutesLength = mockRoutes.mockRoutesLength
|
||||||
|
mockStartIndex = mockRoutes.mockStartIndex
|
||||||
|
|
||||||
|
console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed ${path}`))
|
||||||
|
} catch (error) {
|
||||||
|
console.log(chalk.redBright(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
const Mock = require('mockjs')
|
||||||
|
|
||||||
|
const NameList = []
|
||||||
|
const count = 100
|
||||||
|
|
||||||
|
for (let i = 0; i < count; i++) {
|
||||||
|
NameList.push(Mock.mock({
|
||||||
|
name: '@first'
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
NameList.push({ name: 'mock-Pan' })
|
||||||
|
|
||||||
|
module.exports = [
|
||||||
|
// username search
|
||||||
|
{
|
||||||
|
url: '/vue-element-admin/search/user',
|
||||||
|
type: 'get',
|
||||||
|
response: config => {
|
||||||
|
const { name } = config.query
|
||||||
|
const mockNameList = NameList.filter(item => {
|
||||||
|
const lowerCaseName = item.name.toLowerCase()
|
||||||
|
return !(name && lowerCaseName.indexOf(name.toLowerCase()) < 0)
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
code: 20000,
|
||||||
|
data: { items: mockNameList }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// transaction list
|
||||||
|
{
|
||||||
|
url: '/vue-element-admin/transaction/list',
|
||||||
|
type: 'get',
|
||||||
|
response: _ => {
|
||||||
|
return {
|
||||||
|
code: 20000,
|
||||||
|
data: {
|
||||||
|
total: 20,
|
||||||
|
'items|20': [{
|
||||||
|
order_no: '@guid()',
|
||||||
|
timestamp: +Mock.Random.date('T'),
|
||||||
|
username: '@name()',
|
||||||
|
price: '@float(1000, 15000, 0, 2)',
|
||||||
|
'status|1': ['success', 'pending']
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
|
@ -0,0 +1,98 @@
|
||||||
|
const Mock = require('mockjs')
|
||||||
|
const { deepClone } = require('../utils')
|
||||||
|
const { asyncRoutes, constantRoutes } = require('./routes.js')
|
||||||
|
|
||||||
|
const routes = deepClone([...constantRoutes, ...asyncRoutes])
|
||||||
|
|
||||||
|
const roles = [
|
||||||
|
{
|
||||||
|
key: 'admin',
|
||||||
|
name: 'admin',
|
||||||
|
description: 'Super Administrator. Have access to view all pages.',
|
||||||
|
routes: routes
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'editor',
|
||||||
|
name: 'editor',
|
||||||
|
description: 'Normal Editor. Can see all pages except permission page',
|
||||||
|
routes: routes.filter(i => i.path !== '/permission')// just a mock
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'visitor',
|
||||||
|
name: 'visitor',
|
||||||
|
description: 'Just a visitor. Can only see the home page and the document page',
|
||||||
|
routes: [{
|
||||||
|
path: '',
|
||||||
|
redirect: 'dashboard',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'dashboard',
|
||||||
|
name: 'Dashboard',
|
||||||
|
meta: { title: 'dashboard', icon: 'dashboard' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
module.exports = [
|
||||||
|
// mock get all routes form server
|
||||||
|
{
|
||||||
|
url: '/vue-element-admin/routes',
|
||||||
|
type: 'get',
|
||||||
|
response: _ => {
|
||||||
|
return {
|
||||||
|
code: 20000,
|
||||||
|
data: routes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// mock get all roles form server
|
||||||
|
{
|
||||||
|
url: '/vue-element-admin/roles',
|
||||||
|
type: 'get',
|
||||||
|
response: _ => {
|
||||||
|
return {
|
||||||
|
code: 20000,
|
||||||
|
data: roles
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// add role
|
||||||
|
{
|
||||||
|
url: '/vue-element-admin/role',
|
||||||
|
type: 'post',
|
||||||
|
response: {
|
||||||
|
code: 20000,
|
||||||
|
data: {
|
||||||
|
key: Mock.mock('@integer(300, 5000)')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// update role
|
||||||
|
{
|
||||||
|
url: '/vue-element-admin/role/[A-Za-z0-9]',
|
||||||
|
type: 'put',
|
||||||
|
response: {
|
||||||
|
code: 20000,
|
||||||
|
data: {
|
||||||
|
status: 'success'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// delete role
|
||||||
|
{
|
||||||
|
url: '/vue-element-admin/role/[A-Za-z0-9]',
|
||||||
|
type: 'delete',
|
||||||
|
response: {
|
||||||
|
code: 20000,
|
||||||
|
data: {
|
||||||
|
status: 'success'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
|
@ -0,0 +1,530 @@
|
||||||
|
// Just a mock data
|
||||||
|
|
||||||
|
const constantRoutes = [
|
||||||
|
{
|
||||||
|
path: '/redirect',
|
||||||
|
component: 'layout/Layout',
|
||||||
|
hidden: true,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/redirect/:path*',
|
||||||
|
component: 'views/redirect/index'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/login',
|
||||||
|
component: 'views/login/index',
|
||||||
|
hidden: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/auth-redirect',
|
||||||
|
component: 'views/login/auth-redirect',
|
||||||
|
hidden: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/404',
|
||||||
|
component: 'views/error-page/404',
|
||||||
|
hidden: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/401',
|
||||||
|
component: 'views/error-page/401',
|
||||||
|
hidden: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: 'layout/Layout',
|
||||||
|
redirect: 'dashboard',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'dashboard',
|
||||||
|
component: 'views/dashboard/index',
|
||||||
|
name: 'Dashboard',
|
||||||
|
meta: { title: 'Dashboard', icon: 'dashboard', affix: true }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/documentation',
|
||||||
|
component: 'layout/Layout',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'index',
|
||||||
|
component: 'views/documentation/index',
|
||||||
|
name: 'Documentation',
|
||||||
|
meta: { title: 'Documentation', icon: 'documentation', affix: true }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/guide',
|
||||||
|
component: 'layout/Layout',
|
||||||
|
redirect: '/guide/index',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'index',
|
||||||
|
component: 'views/guide/index',
|
||||||
|
name: 'Guide',
|
||||||
|
meta: { title: 'Guide', icon: 'guide', noCache: true }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const asyncRoutes = [
|
||||||
|
{
|
||||||
|
path: '/permission',
|
||||||
|
component: 'layout/Layout',
|
||||||
|
redirect: '/permission/index',
|
||||||
|
alwaysShow: true,
|
||||||
|
meta: {
|
||||||
|
title: 'Permission',
|
||||||
|
icon: 'lock',
|
||||||
|
roles: ['admin', 'editor']
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'page',
|
||||||
|
component: 'views/permission/page',
|
||||||
|
name: 'PagePermission',
|
||||||
|
meta: {
|
||||||
|
title: 'Page Permission',
|
||||||
|
roles: ['admin']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'directive',
|
||||||
|
component: 'views/permission/directive',
|
||||||
|
name: 'DirectivePermission',
|
||||||
|
meta: {
|
||||||
|
title: 'Directive Permission'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'role',
|
||||||
|
component: 'views/permission/role',
|
||||||
|
name: 'RolePermission',
|
||||||
|
meta: {
|
||||||
|
title: 'Role Permission',
|
||||||
|
roles: ['admin']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: '/icon',
|
||||||
|
component: 'layout/Layout',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'index',
|
||||||
|
component: 'views/icons/index',
|
||||||
|
name: 'Icons',
|
||||||
|
meta: { title: 'Icons', icon: 'icon', noCache: true }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: '/components',
|
||||||
|
component: 'layout/Layout',
|
||||||
|
redirect: 'noRedirect',
|
||||||
|
name: 'ComponentDemo',
|
||||||
|
meta: {
|
||||||
|
title: 'Components',
|
||||||
|
icon: 'component'
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'tinymce',
|
||||||
|
component: 'views/components-demo/tinymce',
|
||||||
|
name: 'TinymceDemo',
|
||||||
|
meta: { title: 'Tinymce' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'markdown',
|
||||||
|
component: 'views/components-demo/markdown',
|
||||||
|
name: 'MarkdownDemo',
|
||||||
|
meta: { title: 'Markdown' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'json-editor',
|
||||||
|
component: 'views/components-demo/json-editor',
|
||||||
|
name: 'JsonEditorDemo',
|
||||||
|
meta: { title: 'Json Editor' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'split-pane',
|
||||||
|
component: 'views/components-demo/split-pane',
|
||||||
|
name: 'SplitpaneDemo',
|
||||||
|
meta: { title: 'SplitPane' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'avatar-upload',
|
||||||
|
component: 'views/components-demo/avatar-upload',
|
||||||
|
name: 'AvatarUploadDemo',
|
||||||
|
meta: { title: 'Avatar Upload' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'dropzone',
|
||||||
|
component: 'views/components-demo/dropzone',
|
||||||
|
name: 'DropzoneDemo',
|
||||||
|
meta: { title: 'Dropzone' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'sticky',
|
||||||
|
component: 'views/components-demo/sticky',
|
||||||
|
name: 'StickyDemo',
|
||||||
|
meta: { title: 'Sticky' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'count-to',
|
||||||
|
component: 'views/components-demo/count-to',
|
||||||
|
name: 'CountToDemo',
|
||||||
|
meta: { title: 'Count To' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'mixin',
|
||||||
|
component: 'views/components-demo/mixin',
|
||||||
|
name: 'ComponentMixinDemo',
|
||||||
|
meta: { title: 'componentMixin' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'back-to-top',
|
||||||
|
component: 'views/components-demo/back-to-top',
|
||||||
|
name: 'BackToTopDemo',
|
||||||
|
meta: { title: 'Back To Top' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'drag-dialog',
|
||||||
|
component: 'views/components-demo/drag-dialog',
|
||||||
|
name: 'DragDialogDemo',
|
||||||
|
meta: { title: 'Drag Dialog' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'drag-select',
|
||||||
|
component: 'views/components-demo/drag-select',
|
||||||
|
name: 'DragSelectDemo',
|
||||||
|
meta: { title: 'Drag Select' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'dnd-list',
|
||||||
|
component: 'views/components-demo/dnd-list',
|
||||||
|
name: 'DndListDemo',
|
||||||
|
meta: { title: 'Dnd List' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'drag-kanban',
|
||||||
|
component: 'views/components-demo/drag-kanban',
|
||||||
|
name: 'DragKanbanDemo',
|
||||||
|
meta: { title: 'Drag Kanban' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/charts',
|
||||||
|
component: 'layout/Layout',
|
||||||
|
redirect: 'noRedirect',
|
||||||
|
name: 'Charts',
|
||||||
|
meta: {
|
||||||
|
title: 'Charts',
|
||||||
|
icon: 'chart'
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'keyboard',
|
||||||
|
component: 'views/charts/keyboard',
|
||||||
|
name: 'KeyboardChart',
|
||||||
|
meta: { title: 'Keyboard Chart', noCache: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'line',
|
||||||
|
component: 'views/charts/line',
|
||||||
|
name: 'LineChart',
|
||||||
|
meta: { title: 'Line Chart', noCache: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'mixchart',
|
||||||
|
component: 'views/charts/mixChart',
|
||||||
|
name: 'MixChart',
|
||||||
|
meta: { title: 'Mix Chart', noCache: true }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/nested',
|
||||||
|
component: 'layout/Layout',
|
||||||
|
redirect: '/nested/menu1/menu1-1',
|
||||||
|
name: 'Nested',
|
||||||
|
meta: {
|
||||||
|
title: 'Nested',
|
||||||
|
icon: 'nested'
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'menu1',
|
||||||
|
component: 'views/nested/menu1/index',
|
||||||
|
name: 'Menu1',
|
||||||
|
meta: { title: 'Menu1' },
|
||||||
|
redirect: '/nested/menu1/menu1-1',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'menu1-1',
|
||||||
|
component: 'views/nested/menu1/menu1-1',
|
||||||
|
name: 'Menu1-1',
|
||||||
|
meta: { title: 'Menu1-1' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'menu1-2',
|
||||||
|
component: 'views/nested/menu1/menu1-2',
|
||||||
|
name: 'Menu1-2',
|
||||||
|
redirect: '/nested/menu1/menu1-2/menu1-2-1',
|
||||||
|
meta: { title: 'Menu1-2' },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'menu1-2-1',
|
||||||
|
component: 'views/nested/menu1/menu1-2/menu1-2-1',
|
||||||
|
name: 'Menu1-2-1',
|
||||||
|
meta: { title: 'Menu1-2-1' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'menu1-2-2',
|
||||||
|
component: 'views/nested/menu1/menu1-2/menu1-2-2',
|
||||||
|
name: 'Menu1-2-2',
|
||||||
|
meta: { title: 'Menu1-2-2' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'menu1-3',
|
||||||
|
component: 'views/nested/menu1/menu1-3',
|
||||||
|
name: 'Menu1-3',
|
||||||
|
meta: { title: 'Menu1-3' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'menu2',
|
||||||
|
name: 'Menu2',
|
||||||
|
component: 'views/nested/menu2/index',
|
||||||
|
meta: { title: 'Menu2' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: '/example',
|
||||||
|
component: 'layout/Layout',
|
||||||
|
redirect: '/example/list',
|
||||||
|
name: 'Example',
|
||||||
|
meta: {
|
||||||
|
title: 'Example',
|
||||||
|
icon: 'example'
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'create',
|
||||||
|
component: 'views/example/create',
|
||||||
|
name: 'CreateArticle',
|
||||||
|
meta: { title: 'Create Article', icon: 'edit' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'edit/:id(\\d+)',
|
||||||
|
component: 'views/example/edit',
|
||||||
|
name: 'EditArticle',
|
||||||
|
meta: { title: 'Edit Article', noCache: true },
|
||||||
|
hidden: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'list',
|
||||||
|
component: 'views/example/list',
|
||||||
|
name: 'ArticleList',
|
||||||
|
meta: { title: 'Article List', icon: 'list' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: '/tab',
|
||||||
|
component: 'layout/Layout',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'index',
|
||||||
|
component: 'views/tab/index',
|
||||||
|
name: 'Tab',
|
||||||
|
meta: { title: 'Tab', icon: 'tab' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: '/error',
|
||||||
|
component: 'layout/Layout',
|
||||||
|
redirect: 'noRedirect',
|
||||||
|
name: 'ErrorPages',
|
||||||
|
meta: {
|
||||||
|
title: 'Error Pages',
|
||||||
|
icon: '404'
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '401',
|
||||||
|
component: 'views/error-page/401',
|
||||||
|
name: 'Page401',
|
||||||
|
meta: { title: 'Page 401', noCache: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '404',
|
||||||
|
component: 'views/error-page/404',
|
||||||
|
name: 'Page404',
|
||||||
|
meta: { title: 'Page 404', noCache: true }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: '/error-log',
|
||||||
|
component: 'layout/Layout',
|
||||||
|
redirect: 'noRedirect',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'log',
|
||||||
|
component: 'views/error-log/index',
|
||||||
|
name: 'ErrorLog',
|
||||||
|
meta: { title: 'Error Log', icon: 'bug' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: '/excel',
|
||||||
|
component: 'layout/Layout',
|
||||||
|
redirect: '/excel/export-excel',
|
||||||
|
name: 'Excel',
|
||||||
|
meta: {
|
||||||
|
title: 'Excel',
|
||||||
|
icon: 'excel'
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'export-excel',
|
||||||
|
component: 'views/excel/export-excel',
|
||||||
|
name: 'ExportExcel',
|
||||||
|
meta: { title: 'Export Excel' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'export-selected-excel',
|
||||||
|
component: 'views/excel/select-excel',
|
||||||
|
name: 'SelectExcel',
|
||||||
|
meta: { title: 'Select Excel' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'export-merge-header',
|
||||||
|
component: 'views/excel/merge-header',
|
||||||
|
name: 'MergeHeader',
|
||||||
|
meta: { title: 'Merge Header' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'upload-excel',
|
||||||
|
component: 'views/excel/upload-excel',
|
||||||
|
name: 'UploadExcel',
|
||||||
|
meta: { title: 'Upload Excel' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: '/zip',
|
||||||
|
component: 'layout/Layout',
|
||||||
|
redirect: '/zip/download',
|
||||||
|
alwaysShow: true,
|
||||||
|
meta: { title: 'Zip', icon: 'zip' },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'download',
|
||||||
|
component: 'views/zip/index',
|
||||||
|
name: 'ExportZip',
|
||||||
|
meta: { title: 'Export Zip' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: '/pdf',
|
||||||
|
component: 'layout/Layout',
|
||||||
|
redirect: '/pdf/index',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'index',
|
||||||
|
component: 'views/pdf/index',
|
||||||
|
name: 'PDF',
|
||||||
|
meta: { title: 'PDF', icon: 'pdf' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/pdf/download',
|
||||||
|
component: 'views/pdf/download',
|
||||||
|
hidden: true
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: '/theme',
|
||||||
|
component: 'layout/Layout',
|
||||||
|
redirect: 'noRedirect',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'index',
|
||||||
|
component: 'views/theme/index',
|
||||||
|
name: 'Theme',
|
||||||
|
meta: { title: 'Theme', icon: 'theme' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: '/clipboard',
|
||||||
|
component: 'layout/Layout',
|
||||||
|
redirect: 'noRedirect',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'index',
|
||||||
|
component: 'views/clipboard/index',
|
||||||
|
name: 'ClipboardDemo',
|
||||||
|
meta: { title: 'Clipboard Demo', icon: 'clipboard' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: '/i18n',
|
||||||
|
component: 'layout/Layout',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'index',
|
||||||
|
component: 'views/i18n-demo/index',
|
||||||
|
name: 'I18n',
|
||||||
|
meta: { title: 'I18n', icon: 'international' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: 'external-link',
|
||||||
|
component: 'layout/Layout',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'https://github.com/PanJiaChen/vue-element-admin',
|
||||||
|
meta: { title: 'External Link', icon: 'link' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{ path: '*', redirect: '/404', hidden: true }
|
||||||
|
]
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
constantRoutes,
|
||||||
|
asyncRoutes
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
|
||||||
|
const tokens = {
|
||||||
|
admin: {
|
||||||
|
token: 'admin-token'
|
||||||
|
},
|
||||||
|
editor: {
|
||||||
|
token: 'editor-token'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const users = {
|
||||||
|
'admin-token': {
|
||||||
|
roles: ['admin'],
|
||||||
|
introduction: 'I am a super administrator',
|
||||||
|
avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
|
||||||
|
name: 'Super Admin'
|
||||||
|
},
|
||||||
|
'editor-token': {
|
||||||
|
roles: ['editor'],
|
||||||
|
introduction: 'I am an editor',
|
||||||
|
avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
|
||||||
|
name: 'Normal Editor'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = [
|
||||||
|
// user login
|
||||||
|
{
|
||||||
|
url: '/vue-element-admin/user/login',
|
||||||
|
type: 'post',
|
||||||
|
response: config => {
|
||||||
|
const { username } = config.body
|
||||||
|
const token = tokens[username]
|
||||||
|
|
||||||
|
// mock error
|
||||||
|
if (!token) {
|
||||||
|
return {
|
||||||
|
code: 60204,
|
||||||
|
message: 'Account and password are incorrect.'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
code: 20000,
|
||||||
|
data: token
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// get user info
|
||||||
|
{
|
||||||
|
url: '/vue-element-admin/user/info\.*',
|
||||||
|
type: 'get',
|
||||||
|
response: config => {
|
||||||
|
const { token } = config.query
|
||||||
|
const info = users[token]
|
||||||
|
|
||||||
|
// mock error
|
||||||
|
if (!info) {
|
||||||
|
return {
|
||||||
|
code: 50008,
|
||||||
|
message: 'Login failed, unable to get user details.'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
code: 20000,
|
||||||
|
data: info
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// user logout
|
||||||
|
{
|
||||||
|
url: '/vue-element-admin/user/logout',
|
||||||
|
type: 'post',
|
||||||
|
response: _ => {
|
||||||
|
return {
|
||||||
|
code: 20000,
|
||||||
|
data: 'success'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
|
@ -0,0 +1,48 @@
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is just a simple version of deep copy
|
||||||
|
* Has a lot of edge cases bug
|
||||||
|
* If you want to use a perfect deep copy, use lodash's _.cloneDeep
|
||||||
|
* @param {Object} source
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
function deepClone(source) {
|
||||||
|
if (!source && typeof source !== 'object') {
|
||||||
|
throw new Error('error arguments', 'deepClone')
|
||||||
|
}
|
||||||
|
const targetObj = source.constructor === Array ? [] : {}
|
||||||
|
Object.keys(source).forEach(keys => {
|
||||||
|
if (source[keys] && typeof source[keys] === 'object') {
|
||||||
|
targetObj[keys] = deepClone(source[keys])
|
||||||
|
} else {
|
||||||
|
targetObj[keys] = source[keys]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return targetObj
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
param2Obj,
|
||||||
|
deepClone
|
||||||
|
}
|
150
package.json
|
@ -1,61 +1,111 @@
|
||||||
{
|
{
|
||||||
"name": "jointcloud",
|
"name": "vue-element-admin",
|
||||||
"version": "0.1.0",
|
"version": "4.4.0",
|
||||||
"private": true,
|
"description": "A magical vue admin. An out-of-box UI solution for enterprise applications. Newest development stack of vue. Lots of awesome features",
|
||||||
"author": "annzee <aannzee@gmail.com>",
|
"author": "Pan <panfree23@gmail.com>",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vue-cli-service serve",
|
"dev": "vue-cli-service serve",
|
||||||
"prod": "vue-cli-service serve --mode production",
|
"lint": "eslint --ext .js,.vue src",
|
||||||
"build": "vue-cli-service build --mode production",
|
"build:prod": "vue-cli-service build",
|
||||||
"lint": "vue-cli-service lint"
|
"build:stage": "vue-cli-service build --mode staging",
|
||||||
|
"preview": "node build/index.js --preview",
|
||||||
|
"new": "plop",
|
||||||
|
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
|
||||||
|
"test:unit": "jest --clearCache && vue-cli-service test:unit",
|
||||||
|
"test:ci": "npm run lint && npm run test:unit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.20.0",
|
"axios": "0.18.1",
|
||||||
"compression-webpack-plugin": "^6.0.4",
|
"clipboard": "2.0.4",
|
||||||
"core-js": "^3.6.5",
|
"codemirror": "5.45.0",
|
||||||
"dedent": "^0.7.0",
|
"core-js": "3.6.5",
|
||||||
"echarts": "^4.9.0",
|
"driver.js": "0.9.5",
|
||||||
"element-ui": "^2.13.2",
|
"dropzone": "5.5.1",
|
||||||
"filemanager-webpack-plugin": "^3.0.0-alpha.4",
|
"echarts": "4.2.1",
|
||||||
"qs": "^6.9.4",
|
"element-ui": "2.13.2",
|
||||||
"uglifyjs-webpack-plugin": "^2.2.0",
|
"file-saver": "2.0.1",
|
||||||
"vue": "^2.6.11",
|
"fuse.js": "3.4.4",
|
||||||
"vue-codemirror": "^4.0.6",
|
"js-cookie": "2.2.0",
|
||||||
"vue-i18n": "^8.22.2",
|
"jsonlint": "1.6.3",
|
||||||
"vue-router": "^3.4.4",
|
"jszip": "3.2.1",
|
||||||
"vuex": "^3.5.1"
|
"normalize.css": "7.0.0",
|
||||||
|
"nprogress": "0.2.0",
|
||||||
|
"path-to-regexp": "2.4.0",
|
||||||
|
"screenfull": "4.2.0",
|
||||||
|
"script-loader": "0.7.2",
|
||||||
|
"sortablejs": "1.8.4",
|
||||||
|
"tui-editor": "1.3.3",
|
||||||
|
"vue": "2.6.10",
|
||||||
|
"vue-count-to": "1.0.13",
|
||||||
|
"vue-router": "3.0.2",
|
||||||
|
"vue-splitpane": "1.0.4",
|
||||||
|
"vuedraggable": "2.20.0",
|
||||||
|
"vuex": "3.1.0",
|
||||||
|
"xlsx": "0.14.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vue/cli-plugin-babel": "~4.5.0",
|
"@vue/cli-plugin-babel": "4.4.4",
|
||||||
"@vue/cli-plugin-eslint": "^4.5.6",
|
"@vue/cli-plugin-eslint": "4.4.4",
|
||||||
"@vue/cli-service": "~4.5.0",
|
"@vue/cli-plugin-unit-jest": "4.4.4",
|
||||||
"@vue/eslint-config-airbnb": "^5.0.2",
|
"@vue/cli-service": "4.4.4",
|
||||||
"babel-eslint": "^10.1.0",
|
"@vue/test-utils": "1.0.0-beta.29",
|
||||||
"eslint": "^6.7.2",
|
"autoprefixer": "9.5.1",
|
||||||
"eslint-plugin-import": "^2.20.2",
|
"babel-eslint": "10.1.0",
|
||||||
"eslint-plugin-vue": "^6.2.2",
|
"babel-jest": "23.6.0",
|
||||||
"node-sass": "^4.14.1",
|
"babel-plugin-dynamic-import-node": "2.3.3",
|
||||||
"sass-loader": "^10.0.2",
|
"chalk": "2.4.2",
|
||||||
"vue-template-compiler": "^2.6.11"
|
"chokidar": "2.1.5",
|
||||||
},
|
"connect": "3.6.6",
|
||||||
"eslintConfig": {
|
"eslint": "6.7.2",
|
||||||
"root": true,
|
"eslint-plugin-vue": "6.2.2",
|
||||||
"env": {
|
"html-webpack-plugin": "3.2.0",
|
||||||
"node": true
|
"husky": "1.3.1",
|
||||||
},
|
"lint-staged": "8.1.5",
|
||||||
"extends": [
|
"mockjs": "1.0.1-beta3",
|
||||||
"plugin:vue/essential",
|
"plop": "2.3.0",
|
||||||
"eslint:recommended",
|
"runjs": "4.3.2",
|
||||||
"@vue/airbnb"
|
"sass": "1.26.2",
|
||||||
],
|
"sass-loader": "8.0.2",
|
||||||
"parserOptions": {
|
"script-ext-html-webpack-plugin": "2.1.3",
|
||||||
"parser": "babel-eslint"
|
"serve-static": "1.13.2",
|
||||||
},
|
"svg-sprite-loader": "4.1.3",
|
||||||
"rules": {}
|
"svgo": "1.2.0",
|
||||||
|
"vue-template-compiler": "2.6.10"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"> 1%",
|
"> 1%",
|
||||||
"last 2 versions",
|
"last 2 versions"
|
||||||
"not dead"
|
],
|
||||||
]
|
"bugs": {
|
||||||
|
"url": "https://github.com/PanJiaChen/vue-element-admin/issues"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.9",
|
||||||
|
"npm": ">= 3.0.0"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"vue",
|
||||||
|
"admin",
|
||||||
|
"dashboard",
|
||||||
|
"element-ui",
|
||||||
|
"boilerplate",
|
||||||
|
"admin-template",
|
||||||
|
"management-system"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"lint-staged": {
|
||||||
|
"src/**/*.{js,vue}": [
|
||||||
|
"eslint --fix",
|
||||||
|
"git add"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"husky": {
|
||||||
|
"hooks": {
|
||||||
|
"pre-commit": "lint-staged"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/PanJiaChen/vue-element-admin.git"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
{{#if template}}
|
||||||
|
<template>
|
||||||
|
<div />
|
||||||
|
</template>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if script}}
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: '{{ properCase name }}',
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
created() {},
|
||||||
|
mounted() {},
|
||||||
|
methods: {}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if style}}
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
{{/if}}
|
|
@ -0,0 +1,55 @@
|
||||||
|
const { notEmpty } = require('../utils.js')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
description: 'generate vue component',
|
||||||
|
prompts: [{
|
||||||
|
type: 'input',
|
||||||
|
name: 'name',
|
||||||
|
message: 'component name please',
|
||||||
|
validate: notEmpty('name')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'checkbox',
|
||||||
|
name: 'blocks',
|
||||||
|
message: 'Blocks:',
|
||||||
|
choices: [{
|
||||||
|
name: '<template>',
|
||||||
|
value: 'template',
|
||||||
|
checked: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '<script>',
|
||||||
|
value: 'script',
|
||||||
|
checked: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'style',
|
||||||
|
value: 'style',
|
||||||
|
checked: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
validate(value) {
|
||||||
|
if (value.indexOf('script') === -1 && value.indexOf('template') === -1) {
|
||||||
|
return 'Components require at least a <script> or <template> tag.'
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
actions: data => {
|
||||||
|
const name = '{{properCase name}}'
|
||||||
|
const actions = [{
|
||||||
|
type: 'add',
|
||||||
|
path: `src/components/${name}/index.vue`,
|
||||||
|
templateFile: 'plop-templates/component/index.hbs',
|
||||||
|
data: {
|
||||||
|
name: name,
|
||||||
|
template: data.blocks.includes('template'),
|
||||||
|
script: data.blocks.includes('script'),
|
||||||
|
style: data.blocks.includes('style')
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
|
||||||
|
return actions
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
{{#if state}}
|
||||||
|
const state = {}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if mutations}}
|
||||||
|
const mutations = {}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if actions}}
|
||||||
|
const actions = {}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
namespaced: true,
|
||||||
|
{{options}}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
const { notEmpty } = require('../utils.js')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
description: 'generate store',
|
||||||
|
prompts: [{
|
||||||
|
type: 'input',
|
||||||
|
name: 'name',
|
||||||
|
message: 'store name please',
|
||||||
|
validate: notEmpty('name')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'checkbox',
|
||||||
|
name: 'blocks',
|
||||||
|
message: 'Blocks:',
|
||||||
|
choices: [{
|
||||||
|
name: 'state',
|
||||||
|
value: 'state',
|
||||||
|
checked: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'mutations',
|
||||||
|
value: 'mutations',
|
||||||
|
checked: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'actions',
|
||||||
|
value: 'actions',
|
||||||
|
checked: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
validate(value) {
|
||||||
|
if (!value.includes('state') || !value.includes('mutations')) {
|
||||||
|
return 'store require at least state and mutations'
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
actions(data) {
|
||||||
|
const name = '{{name}}'
|
||||||
|
const { blocks } = data
|
||||||
|
const options = ['state', 'mutations']
|
||||||
|
const joinFlag = `,
|
||||||
|
`
|
||||||
|
if (blocks.length === 3) {
|
||||||
|
options.push('actions')
|
||||||
|
}
|
||||||
|
|
||||||
|
const actions = [{
|
||||||
|
type: 'add',
|
||||||
|
path: `src/store/modules/${name}.js`,
|
||||||
|
templateFile: 'plop-templates/store/index.hbs',
|
||||||
|
data: {
|
||||||
|
options: options.join(joinFlag),
|
||||||
|
state: blocks.includes('state'),
|
||||||
|
mutations: blocks.includes('mutations'),
|
||||||
|
actions: blocks.includes('actions')
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
return actions
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
exports.notEmpty = name => v =>
|
||||||
|
!v || v.trim() === '' ? `${name} is required` : true
|
|
@ -0,0 +1,26 @@
|
||||||
|
{{#if template}}
|
||||||
|
<template>
|
||||||
|
<div />
|
||||||
|
</template>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if script}}
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: '{{ properCase name }}',
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
created() {},
|
||||||
|
mounted() {},
|
||||||
|
methods: {}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if style}}
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
{{/if}}
|
|
@ -0,0 +1,55 @@
|
||||||
|
const { notEmpty } = require('../utils.js')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
description: 'generate a view',
|
||||||
|
prompts: [{
|
||||||
|
type: 'input',
|
||||||
|
name: 'name',
|
||||||
|
message: 'view name please',
|
||||||
|
validate: notEmpty('name')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'checkbox',
|
||||||
|
name: 'blocks',
|
||||||
|
message: 'Blocks:',
|
||||||
|
choices: [{
|
||||||
|
name: '<template>',
|
||||||
|
value: 'template',
|
||||||
|
checked: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '<script>',
|
||||||
|
value: 'script',
|
||||||
|
checked: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'style',
|
||||||
|
value: 'style',
|
||||||
|
checked: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
validate(value) {
|
||||||
|
if (value.indexOf('script') === -1 && value.indexOf('template') === -1) {
|
||||||
|
return 'View require at least a <script> or <template> tag.'
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
actions: data => {
|
||||||
|
const name = '{{name}}'
|
||||||
|
const actions = [{
|
||||||
|
type: 'add',
|
||||||
|
path: `src/views/${name}/index.vue`,
|
||||||
|
templateFile: 'plop-templates/view/index.hbs',
|
||||||
|
data: {
|
||||||
|
name: name,
|
||||||
|
template: data.blocks.includes('template'),
|
||||||
|
script: data.blocks.includes('script'),
|
||||||
|
style: data.blocks.includes('style')
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
|
||||||
|
return actions
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
const viewGenerator = require('./plop-templates/view/prompt')
|
||||||
|
const componentGenerator = require('./plop-templates/component/prompt')
|
||||||
|
const storeGenerator = require('./plop-templates/store/prompt.js')
|
||||||
|
|
||||||
|
module.exports = function(plop) {
|
||||||
|
plop.setGenerator('view', viewGenerator)
|
||||||
|
plop.setGenerator('component', componentGenerator)
|
||||||
|
plop.setGenerator('store', storeGenerator)
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
autoprefixer: {}
|
||||||
|
}
|
||||||
|
}
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 66 KiB |
|
@ -1,30 +1,14 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
<meta name="renderer" content="webkit">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
<title><%= webpackConfig.name %></title>
|
||||||
<!-- 使用CDN的CSS文件 -->
|
|
||||||
<% for (var i in htmlWebpackPlugin.options.cdn &&
|
|
||||||
htmlWebpackPlugin.options.cdn.css) { %>
|
|
||||||
<link rel="stylesheet" href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" />
|
|
||||||
<% } %>
|
|
||||||
|
|
||||||
<!-- 使用CDN的JS文件 -->
|
|
||||||
<% for (var i in htmlWebpackPlugin.options.cdn &&
|
|
||||||
htmlWebpackPlugin.options.cdn.js) { %>
|
|
||||||
<script
|
|
||||||
type="text/javascript"
|
|
||||||
src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"
|
|
||||||
></script>
|
|
||||||
<% } %>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>
|
|
||||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
|
||||||
</noscript>
|
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<!-- built files will be auto injected -->
|
<!-- built files will be auto injected -->
|
||||||
</body>
|
</body>
|
||||||
|
|
15
src/App.vue
|
@ -5,18 +5,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App'
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
#app {
|
|
||||||
font-family: Avenir, Helvetica, Arial, sans-serif;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
text-align: center;
|
|
||||||
color: #2c3e50;
|
|
||||||
}
|
}
|
||||||
</style>
|
</script>
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
import common from './common';
|
|
||||||
import cloudStorage from './cloudStorage';
|
|
||||||
import cloudComputation from './cloudComputation';
|
|
||||||
import serviceRecommendation from './serviceRecommendation';
|
|
||||||
|
|
||||||
export default { common, cloudStorage, cloudComputation, serviceRecommendation };
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function fetchList(query) {
|
||||||
|
return request({
|
||||||
|
url: '/vue-element-admin/article/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchArticle(id) {
|
||||||
|
return request({
|
||||||
|
url: '/vue-element-admin/article/detail',
|
||||||
|
method: 'get',
|
||||||
|
params: { id }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchPv(pv) {
|
||||||
|
return request({
|
||||||
|
url: '/vue-element-admin/article/pv',
|
||||||
|
method: 'get',
|
||||||
|
params: { pv }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createArticle(data) {
|
||||||
|
return request({
|
||||||
|
url: '/vue-element-admin/article/create',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateArticle(data) {
|
||||||
|
return request({
|
||||||
|
url: '/vue-element-admin/article/update',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,50 +0,0 @@
|
||||||
import request from '@/utils/request';
|
|
||||||
|
|
||||||
// 云计算接口
|
|
||||||
export default {
|
|
||||||
createFunction(query) {
|
|
||||||
return request({
|
|
||||||
url: '/function/createFunction',
|
|
||||||
method: 'post',
|
|
||||||
data: query,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
deleteFunctionByName() {
|
|
||||||
return request({
|
|
||||||
url: '/function/delete/functionByName',
|
|
||||||
method: 'delete',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
deleteFunction(functionId) {
|
|
||||||
return request({
|
|
||||||
url: `/function/deleteFunction/${functionId}`,
|
|
||||||
method: 'delete',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
getFunctionByFunctionName() {
|
|
||||||
return request({
|
|
||||||
url: '/function/delete/functionByName',
|
|
||||||
method: 'get',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
invokeFunction(query) {
|
|
||||||
return request({
|
|
||||||
url: '/function/invokeFunction',
|
|
||||||
method: 'post',
|
|
||||||
data: query,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
listFunctions(query) {
|
|
||||||
return request({
|
|
||||||
url: '/function/lists',
|
|
||||||
method: 'get',
|
|
||||||
params: query || { page: 1, size: 10 },
|
|
||||||
});
|
|
||||||
},
|
|
||||||
updateFunction() {
|
|
||||||
return request({
|
|
||||||
url: '/function/updateFunction',
|
|
||||||
method: 'put',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -1,45 +0,0 @@
|
||||||
import request from '@/utils/request';
|
|
||||||
|
|
||||||
// 云存储接口
|
|
||||||
export default {
|
|
||||||
makeBucket(query) {
|
|
||||||
return request({
|
|
||||||
url: '/storage/makeBucket',
|
|
||||||
method: 'post',
|
|
||||||
params: query,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
listBuckets() {
|
|
||||||
return request({
|
|
||||||
url: '/storage/listBuckets',
|
|
||||||
method: 'get',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
listCloudFiles() {
|
|
||||||
return request({
|
|
||||||
url: '/storage/listCloudFiles',
|
|
||||||
method: 'get',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
uploadFile(query) {
|
|
||||||
return request({
|
|
||||||
url: '/storage/uploadFile',
|
|
||||||
method: 'post',
|
|
||||||
params: query,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
downloadFile() {
|
|
||||||
return request({
|
|
||||||
url: '/storage/downloadFile',
|
|
||||||
method: 'get',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
deleteFile(query) {
|
|
||||||
return request({
|
|
||||||
url: '/storage/deleteFile',
|
|
||||||
method: 'post',
|
|
||||||
params: query,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
};
|
|
|
@ -1,18 +0,0 @@
|
||||||
import request from '@/utils/request';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
create(query) {
|
|
||||||
return request({
|
|
||||||
url: '/api/register',
|
|
||||||
method: 'post',
|
|
||||||
params: query,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
login(query) {
|
|
||||||
return request({
|
|
||||||
url: '/login',
|
|
||||||
method: 'post',
|
|
||||||
params: query,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getToken() {
|
||||||
|
return request({
|
||||||
|
url: '/qiniu/upload/token', // 假地址 自行替换
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function searchUser(name) {
|
||||||
|
return request({
|
||||||
|
url: '/vue-element-admin/search/user',
|
||||||
|
method: 'get',
|
||||||
|
params: { name }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function transactionList(query) {
|
||||||
|
return request({
|
||||||
|
url: '/vue-element-admin/transaction/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getRoutes() {
|
||||||
|
return request({
|
||||||
|
url: '/vue-element-admin/routes',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRoles() {
|
||||||
|
return request({
|
||||||
|
url: '/vue-element-admin/roles',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addRole(data) {
|
||||||
|
return request({
|
||||||
|
url: '/vue-element-admin/role',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateRole(id, data) {
|
||||||
|
return request({
|
||||||
|
url: `/vue-element-admin/role/${id}`,
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteRole(id) {
|
||||||
|
return request({
|
||||||
|
url: `/vue-element-admin/role/${id}`,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,26 +0,0 @@
|
||||||
import request from '@/utils/request';
|
|
||||||
|
|
||||||
// 云推荐接口
|
|
||||||
export default {
|
|
||||||
scoreTotal(query) {
|
|
||||||
return request({
|
|
||||||
url: '/scoreTotal/page',
|
|
||||||
method: 'get',
|
|
||||||
params: query
|
|
||||||
});
|
|
||||||
},
|
|
||||||
scoreCost(query) {
|
|
||||||
return request({
|
|
||||||
url: '/scoreCost/page',
|
|
||||||
method: 'get',
|
|
||||||
params: query
|
|
||||||
});
|
|
||||||
},
|
|
||||||
score(query) {
|
|
||||||
return request({
|
|
||||||
url: '/score/page',
|
|
||||||
method: 'get',
|
|
||||||
params: query
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function login(data) {
|
||||||
|
return request({
|
||||||
|
url: '/vue-element-admin/user/login',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getInfo(token) {
|
||||||
|
return request({
|
||||||
|
url: '/vue-element-admin/user/info',
|
||||||
|
method: 'get',
|
||||||
|
params: { token }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function logout() {
|
||||||
|
return request({
|
||||||
|
url: '/vue-element-admin/user/logout',
|
||||||
|
method: 'post'
|
||||||
|
})
|
||||||
|
}
|
After Width: | Height: | Size: 160 KiB |
After Width: | Height: | Size: 96 KiB |
After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 430 KiB |
Before Width: | Height: | Size: 80 KiB |
Before Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 354 KiB |
Before Width: | Height: | Size: 178 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 397 KiB |
Before Width: | Height: | Size: 572 KiB |
Before Width: | Height: | Size: 388 KiB |
Before Width: | Height: | Size: 152 KiB |
Before Width: | Height: | Size: 318 KiB |
Before Width: | Height: | Size: 683 KiB |
Before Width: | Height: | Size: 1.2 MiB |
Before Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 279 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 151 KiB |
Before Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 729 KiB |
Before Width: | Height: | Size: 228 KiB |
Before Width: | Height: | Size: 113 KiB |
Before Width: | Height: | Size: 184 KiB |
Before Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 697 KiB |
Before Width: | Height: | Size: 206 KiB |
Before Width: | Height: | Size: 525 KiB |
Before Width: | Height: | Size: 533 KiB |
Before Width: | Height: | Size: 165 KiB |
Before Width: | Height: | Size: 280 KiB |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 119 KiB |
Before Width: | Height: | Size: 65 KiB |
Before Width: | Height: | Size: 119 KiB |
Before Width: | Height: | Size: 148 KiB |
Before Width: | Height: | Size: 143 KiB |
Before Width: | Height: | Size: 116 KiB |
Before Width: | Height: | Size: 152 KiB |
Before Width: | Height: | Size: 163 KiB |
Before Width: | Height: | Size: 149 KiB |
Before Width: | Height: | Size: 58 KiB |