diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5b7c739
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/*.rar
diff --git a/vue/.editorconfig b/vue/.editorconfig
new file mode 100644
index 0000000..3454886
--- /dev/null
+++ b/vue/.editorconfig
@@ -0,0 +1,14 @@
+# https://editorconfig.org
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.md]
+insert_final_newline = false
+trim_trailing_whitespace = false
diff --git a/vue/.env.development b/vue/.env.development
new file mode 100644
index 0000000..fe21aeb
--- /dev/null
+++ b/vue/.env.development
@@ -0,0 +1,15 @@
+# just a flag
+ENV = 'development'
+
+# base api
+VUE_APP_BASE_API = '/dev-api'
+VUE_APP_BASE_API_ADMIN = 'http://114.116.225.148:8002'
+port='9528'
+# vue-cli uses the VUE_CLI_BABEL_TRANSPILE_MODULES environment variable,
+# to control whether the babel-plugin-dynamic-import-node plugin is enabled.
+# It only does one thing by converting all import() to require().
+# This configuration can significantly increase the speed of hot updates,
+# when you have a large number of pages.
+# Detail: https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/babel-preset-app/index.js
+
+VUE_CLI_BABEL_TRANSPILE_MODULES = true
diff --git a/vue/.env.production b/vue/.env.production
new file mode 100644
index 0000000..80c8103
--- /dev/null
+++ b/vue/.env.production
@@ -0,0 +1,6 @@
+# just a flag
+ENV = 'production'
+
+# base api
+VUE_APP_BASE_API = '/prod-api'
+
diff --git a/vue/.env.staging b/vue/.env.staging
new file mode 100644
index 0000000..a8793a0
--- /dev/null
+++ b/vue/.env.staging
@@ -0,0 +1,8 @@
+NODE_ENV = production
+
+# just a flag
+ENV = 'staging'
+
+# base api
+VUE_APP_BASE_API = '/stage-api'
+
diff --git a/vue/.eslintignore b/vue/.eslintignore
new file mode 100644
index 0000000..99b9edd
--- /dev/null
+++ b/vue/.eslintignore
@@ -0,0 +1,4 @@
+build/*.js
+src
+public
+dist
diff --git a/vue/.eslintrc.js b/vue/.eslintrc.js
new file mode 100644
index 0000000..b3382c0
--- /dev/null
+++ b/vue/.eslintrc.js
@@ -0,0 +1,15 @@
+module.exports = {
+ root: true,
+ env: {
+ node: true,
+ es6: true
+ },
+ rules: {
+ 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
+ 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
+ },
+ parserOptions: {
+ parser: 'babel-eslint',
+ sourceType: "module",
+ }
+}
diff --git a/vue/.gitignore b/vue/.gitignore
new file mode 100644
index 0000000..d3d938d
--- /dev/null
+++ b/vue/.gitignore
@@ -0,0 +1,24 @@
+.DS_Store
+node_modules/
+dist/
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+**/*.log
+
+tests/**/coverage/
+tests/e2e/reports
+selenium-debug.log
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.local
+
+package-lock.json
+yarn.lock
+/.vs
diff --git a/vue/.travis.yml b/vue/.travis.yml
new file mode 100644
index 0000000..f4be7a0
--- /dev/null
+++ b/vue/.travis.yml
@@ -0,0 +1,5 @@
+language: node_js
+node_js: 10
+script: npm run test
+notifications:
+ email: false
diff --git a/vue/LICENSE b/vue/LICENSE
new file mode 100644
index 0000000..6151575
--- /dev/null
+++ b/vue/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017-present PanJiaChen
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vue/README.md b/vue/README.md
new file mode 100644
index 0000000..8b2c19c
--- /dev/null
+++ b/vue/README.md
@@ -0,0 +1,84 @@
+
+
+
+**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
+
+- [Getting started](#getting-started)
+- [Build](#build)
+- [Advanced](#advanced)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## Getting started
+
+```bash
+# clone the project
+git clone -b i18n git@github.com:PanJiaChen/vue-element-admin.git
+
+# enter the project directory
+cd vue-element-admin
+
+# install dependency
+npm install
+
+# develop
+npm run dev
+```
+
+This will automatically open http://localhost:9527
+
+## Build
+
+```bash
+# build for test environment
+npm run build:stage
+
+# build for production environment
+npm run build:prod
+```
+
+## 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
+```
+
+
diff --git a/vue/babel.config.js b/vue/babel.config.js
new file mode 100644
index 0000000..ba17966
--- /dev/null
+++ b/vue/babel.config.js
@@ -0,0 +1,5 @@
+module.exports = {
+ presets: [
+ '@vue/app'
+ ]
+}
diff --git a/vue/build/index.js b/vue/build/index.js
new file mode 100644
index 0000000..0c57de2
--- /dev/null
+++ b/vue/build/index.js
@@ -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}`)
+}
diff --git a/vue/jest.config.js b/vue/jest.config.js
new file mode 100644
index 0000000..143cdc8
--- /dev/null
+++ b/vue/jest.config.js
@@ -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: {
+ '^@/(.*)$': '/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: '/tests/unit/coverage',
+ // 'collectCoverage': true,
+ 'coverageReporters': [
+ 'lcov',
+ 'text-summary'
+ ],
+ testURL: 'http://localhost/'
+}
diff --git a/vue/jsconfig.json b/vue/jsconfig.json
new file mode 100644
index 0000000..958df04
--- /dev/null
+++ b/vue/jsconfig.json
@@ -0,0 +1,9 @@
+{
+ "compilerOptions": {
+ "baseUrl": "./",
+ "paths": {
+ "@/*": ["src/*"]
+ }
+ },
+ "exclude": ["node_modules", "dist"]
+}
\ No newline at end of file
diff --git a/vue/mock/article.js b/vue/mock/article.js
new file mode 100644
index 0000000..50218ae
--- /dev/null
+++ b/vue/mock/article.js
@@ -0,0 +1,116 @@
+import Mock from 'mockjs'
+
+const List = []
+const count = 100
+
+const baseContent = 'I am testing data, I am testing data.

'
+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']
+ }))
+}
+
+export default [
+ {
+ 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'
+ }
+ }
+ }
+]
+
diff --git a/vue/mock/common.js b/vue/mock/common.js
new file mode 100644
index 0000000..164f796
--- /dev/null
+++ b/vue/mock/common.js
@@ -0,0 +1,278 @@
+import Mock from 'mockjs'
+//表格字段数据
+const ListField = [{
+ "level": 1,
+ "children": [{"level": 2, "name": "666", "pid": 1, "id": 2, "label": "666"}, {
+ "level": 2,
+ "name": "777",
+ "pid": 1,
+ "id": 3,
+ "label": "777"
+ }],
+ "name": "办公室",
+ "pid": 0,
+ "id": 1,
+ "label": "办公室"
+}, {"level": 2, "name": "666", "pid": 1, "id": 2, "label": "666"}, {
+ "level": 2,
+ "name": "777",
+ "pid": 1,
+ "id": 3,
+ "label": "777"
+}]
+//表格list数据
+const roleList = [{
+ "name": "系统管理角色",
+ "pid": 1,
+ "list": [{
+ "remark": "超级管理员",
+ "pid": 1,
+ "rules": {"bi": [], "crm": []},
+ "id": 1,
+ "label": null,
+ "title": "超级管理员",
+ "type": 5,
+ "status": 1
+ }, {
+ "remark": "系统设置管理员",
+ "pid": 1,
+ "rules": {"bi": [], "crm": []},
+ "id": 2,
+ "label": null,
+ "title": "系统设置管理员",
+ "type": 2,
+ "status": 1
+ }, {
+ "remark": "部门与员工管理员",
+ "pid": 1,
+ "rules": {"bi": [], "crm": []},
+ "id": 3,
+ "label": null,
+ "title": "部门与员工管理员",
+ "type": 5,
+ "status": 1
+ }, {
+ "remark": "审批流管理员",
+ "pid": 1,
+ "rules": {"bi": [], "crm": []},
+ "id": 4,
+ "label": null,
+ "title": "审批流管理员",
+ "type": 5,
+ "status": 1
+ }, {
+ "remark": "工作台管理员",
+ "pid": 1,
+ "rules": {"bi": [], "crm": []},
+ "id": 5,
+ "label": null,
+ "title": "工作台管理员",
+ "type": 5,
+ "status": 1
+ }, {
+ "remark": "客户管理员",
+ "pid": 1,
+ "rules": {"bi": [], "crm": []},
+ "id": 6,
+ "label": null,
+ "title": "客户管理员",
+ "type": 5,
+ "status": 1
+ }]
+}, {
+ "name": "客户管理角色",
+ "pid": 2,
+ "list": [{
+ "remark": "销售经理角色",
+ "pid": 2,
+ "rules": {
+ "bi": [],
+ "crm": [9, 17, 18, 19, 20, 21, 22, 23, 24, 25, 10, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 191, 11, 40, 41, 42, 43, 44, 45, 107, 108, 12, 46, 47, 48, 49, 50, 51, 52, 13, 53, 54, 55, 56, 57, 58, 59, 14, 60, 61, 62, 63, 64, 15, 65, 66, 67, 68, 69, 109, 110, 127, 128, 129, 130, 131]
+ },
+ "id": 8,
+ "label": null,
+ "title": "销售经理角色",
+ "type": 2,
+ "status": 1
+ }, {
+ "remark": "行政管理",
+ "pid": 2,
+ "rules": {"bi": [], "crm": []},
+ "id": 9,
+ "label": null,
+ "title": "行政管理",
+ "type": 1,
+ "status": 1
+ }, {
+ "remark": "财务角色",
+ "pid": 2,
+ "rules": {"bi": [], "crm": []},
+ "id": 10,
+ "label": null,
+ "title": "财务角色",
+ "type": 1,
+ "status": 1
+ }, {
+ "remark": "销售员角色",
+ "pid": 2,
+ "rules": {"bi": [], "crm": []},
+ "id": 11,
+ "label": null,
+ "title": "销售员角色",
+ "type": 2,
+ "status": 1
+ }]
+}, {
+ "name": "办公管理角色",
+ "pid": 7,
+ "list": [{
+ "remark": "公告管理员",
+ "pid": 7,
+ "rules": {"bi": [], "crm": []},
+ "id": 7,
+ "label": null,
+ "title": "公告管理员",
+ "type": 5,
+ "status": 1
+ }]
+}, {
+ "name": "项目管理角色",
+ "pid": 8,
+ "list": [{
+ "remark": "项目管理员",
+ "pid": 8,
+ "rules": {"bi": [], "crm": []},
+ "id": 12,
+ "label": 1,
+ "title": "项目管理员",
+ "type": 5,
+ "status": 1
+ }, {
+ "remark": "测试项目",
+ "pid": 8,
+ "rules": {"bi": [], "crm": []},
+ "id": 47,
+ "label": null,
+ "title": "测试项目",
+ "type": 5,
+ "status": 1
+ }]
+}, {"name": "自定义角色", "pid": 0, "list": []}]
+
+const userList = {
+ "totalRow": 2,
+ "pageNumber": 1,
+ "firstPage": true,
+ "lastPage": true,
+ "totalPage": 1,
+ "pageSize": 15,
+ "list": [{
+ "deptName": "办公室",
+ "img": "",
+ "createTime": "2019-02-13 15:43:26",
+ "roleId": "1",
+ "sex": null,
+ "mobile": "12312341234",
+ "realname": "admin",
+ "parentName": null,
+ "post": "1",
+ "userId": 3,
+ "parentId": 0,
+ "roleName": "超级管理员",
+ "deptId": 1,
+ "email": null,
+ "username": "admin",
+ "status": 1
+ }, {
+ "deptName": "办公室",
+ "img": null,
+ "createTime": "2020-11-10 11:01:49",
+ "roleId": "3",
+ "sex": null,
+ "mobile": "13364306255",
+ "realname": "ttt",
+ "parentName": null,
+ "post": null,
+ "userId": 4,
+ "parentId": null,
+ "roleName": "部门与员工管理员",
+ "deptId": 1,
+ "email": null,
+ "username": "13364306255",
+ "status": 1
+ }]
+}
+
+const sceneList =
+ [{
+ "isSystem": 1,
+ "bydata": null,
+ "data": "{\"is_transform\":{\"condition\":\"is\",\"name\":\"is_transform\",\"value\":0}}",
+ "sceneId": 22,
+ "name": "全部线索",
+ "isDefault": 0
+ }, {
+ "isSystem": 1,
+ "bydata": null,
+ "data": "{\"owner_user_id\":{\"condition\":\"is\",\"name\":\"owner_user_id\",\"value\":3},\"is_transform\":{\"condition\":\"is\",\"name\":\"is_transform\",\"value\":0}}",
+ "sceneId": 23,
+ "name": "我负责的线索",
+ "isDefault": 0
+ }, {
+ "isSystem": 1,
+ "bydata": null,
+ "data": "{\"owner_user_id\":{\"condition\":\"in\",\"name\":\"owner_user_id\",\"value\":\"0\"},\"is_transform\":{\"condition\":\"is\",\"name\":\"is_transform\",\"value\":0}}",
+ "sceneId": 24,
+ "name": "下属负责的线索",
+ "isDefault": 0
+ }, {
+ "isSystem": 1,
+ "bydata": "transform",
+ "data": "{\"is_transform\":{\"condition\":\"is\",\"name\":\"is_transform\",\"value\":\"1\"}}",
+ "sceneId": 25,
+ "name": "已转化的线索",
+ "isDefault": 0
+ }]
+export default [
+ {
+ url: '/vue-element-admin/system/dept/queryDeptTreed',
+ type: 'get',
+ response: _ => {
+ return {
+ "code": 20000,
+ "data": ListField
+ }
+ }
+ },
+ {
+ url: '/vue-element-admin/system/role/getAllRoleList',
+ type: 'get',
+ response: _ => {
+ return {
+ "code": 20000,
+ "data": roleList,
+ }
+ }
+ },
+ {
+ url: '/vue-element-admin/system/user/queryUserList',
+ type: 'get',
+ response: _ => {
+ return {
+ "code": 20000,
+ "data": userList,
+ }
+ }
+ },
+ {
+ url: '/vue-element-admin/system/scene/getAllsceneList',
+ type: 'get',
+ response: _ => {
+ return {
+ "code": 20000,
+ "data": sceneList
+ }
+ }
+ },
+]
+
diff --git a/vue/mock/index.js b/vue/mock/index.js
new file mode 100644
index 0000000..495bb51
--- /dev/null
+++ b/vue/mock/index.js
@@ -0,0 +1,74 @@
+import Mock from 'mockjs'
+import { param2Obj } from '../src/utils'
+
+import user from './user'
+import role from './role'
+import article from './article'
+import search from './remote-search'
+import ux from './ux'
+import common from './common'
+const mocks = [
+ ...user,
+ ...role,
+ ...article,
+ ...search,
+ ...ux,
+ ...common
+]
+
+// 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).
+export 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))
+ }
+}
+
+// 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))
+ }
+ }
+}
+
+export default mocks.map(route => {
+ return responseFake(route.url, route.type, route.response)
+})
diff --git a/vue/mock/mock-server.js b/vue/mock/mock-server.js
new file mode 100644
index 0000000..4c4cb2a
--- /dev/null
+++ b/vue/mock/mock-server.js
@@ -0,0 +1,68 @@
+const chokidar = require('chokidar')
+const bodyParser = require('body-parser')
+const chalk = require('chalk')
+const path = require('path')
+
+const mockDir = path.join(process.cwd(), 'mock')
+
+function registerRoutes(app) {
+ let mockLastIndex
+ const { default: mocks } = require('./index.js')
+ for (const mock of mocks) {
+ app[mock.type](mock.url, mock.response)
+ mockLastIndex = app._router.stack.length
+ }
+ const mockRoutesLength = Object.keys(mocks).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)]
+ }
+ })
+}
+
+module.exports = app => {
+ // es6 polyfill
+ require('@babel/register')
+
+ // 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))
+ }
+ }
+ })
+}
diff --git a/vue/mock/remote-search.js b/vue/mock/remote-search.js
new file mode 100644
index 0000000..60809cb
--- /dev/null
+++ b/vue/mock/remote-search.js
@@ -0,0 +1,51 @@
+import Mock from 'mockjs'
+
+const NameList = []
+const count = 100
+
+for (let i = 0; i < count; i++) {
+ NameList.push(Mock.mock({
+ name: '@first'
+ }))
+}
+NameList.push({ name: 'mock-Pan' })
+
+export default [
+ // 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']
+ }]
+ }
+ }
+ }
+ }
+]
diff --git a/vue/mock/role/index.js b/vue/mock/role/index.js
new file mode 100644
index 0000000..d957493
--- /dev/null
+++ b/vue/mock/role/index.js
@@ -0,0 +1,98 @@
+import Mock from 'mockjs'
+import { deepClone } from '../../src/utils/index.js'
+import { asyncRoutes, constantRoutes } from './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' }
+ }
+ ]
+ }]
+ }
+]
+
+export default [
+ // 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'
+ }
+ }
+ }
+]
diff --git a/vue/mock/role/routes.js b/vue/mock/role/routes.js
new file mode 100644
index 0000000..c465456
--- /dev/null
+++ b/vue/mock/role/routes.js
@@ -0,0 +1,525 @@
+// Just a mock data
+
+export 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 }
+ }
+ ]
+ }
+]
+
+export 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: 'pagePermission',
+ roles: ['admin']
+ }
+ },
+ {
+ path: 'directive',
+ component: 'views/permission/directive',
+ name: 'DirectivePermission',
+ meta: {
+ title: 'directivePermission'
+ }
+ },
+ {
+ path: 'role',
+ component: 'views/permission/role',
+ name: 'RolePermission',
+ meta: {
+ title: 'rolePermission',
+ 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: 'jsonEditor' }
+ },
+ {
+ 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: 'avatarUpload' }
+ },
+ {
+ 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: 'countTo' }
+ },
+ {
+ 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: 'backToTop' }
+ },
+ {
+ path: 'drag-dialog',
+ component: 'views/components-demo/drag-dialog',
+ name: 'DragDialogDemo',
+ meta: { title: 'dragDialog' }
+ },
+ {
+ path: 'drag-select',
+ component: 'views/components-demo/drag-select',
+ name: 'DragSelectDemo',
+ meta: { title: 'dragSelect' }
+ },
+ {
+ path: 'dnd-list',
+ component: 'views/components-demo/dnd-list',
+ name: 'DndListDemo',
+ meta: { title: 'dndList' }
+ },
+ {
+ path: 'drag-kanban',
+ component: 'views/components-demo/drag-kanban',
+ name: 'DragKanbanDemo',
+ meta: { title: 'dragKanban' }
+ }
+ ]
+ },
+ {
+ 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: 'keyboardChart', noCache: true }
+ },
+ {
+ path: 'line',
+ component: 'views/charts/line',
+ name: 'LineChart',
+ meta: { title: 'lineChart', noCache: true }
+ },
+ {
+ path: 'mixchart',
+ component: 'views/charts/mixChart',
+ name: 'MixChart',
+ meta: { title: 'mixChart', 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: 'createArticle', icon: 'edit' }
+ },
+ {
+ path: 'edit/:id(\\d+)',
+ component: 'views/example/edit',
+ name: 'EditArticle',
+ meta: { title: 'editArticle', noCache: true },
+ hidden: true
+ },
+ {
+ path: 'list',
+ component: 'views/example/list',
+ name: 'ArticleList',
+ meta: { title: 'articleList', 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: 'errorPages',
+ icon: '404'
+ },
+ children: [
+ {
+ path: '401',
+ component: 'views/error-page/401',
+ name: 'Page401',
+ meta: { title: 'page401', noCache: true }
+ },
+ {
+ path: '404',
+ component: 'views/error-page/404',
+ name: 'Page404',
+ meta: { title: 'page404', noCache: true }
+ }
+ ]
+ },
+
+ {
+ path: '/error-log',
+ component: 'layout/Layout',
+ redirect: 'noRedirect',
+ children: [
+ {
+ path: 'log',
+ component: 'views/error-log/index',
+ name: 'ErrorLog',
+ meta: { title: 'errorLog', 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: 'exportExcel' }
+ },
+ {
+ path: 'export-selected-excel',
+ component: 'views/excel/select-excel',
+ name: 'SelectExcel',
+ meta: { title: 'selectExcel' }
+ },
+ {
+ path: 'export-merge-header',
+ component: 'views/excel/merge-header',
+ name: 'MergeHeader',
+ meta: { title: 'mergeHeader' }
+ },
+ {
+ path: 'upload-excel',
+ component: 'views/excel/upload-excel',
+ name: 'UploadExcel',
+ meta: { title: 'uploadExcel' }
+ }
+ ]
+ },
+
+ {
+ 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: 'exportZip' }
+ }
+ ]
+ },
+
+ {
+ 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: 'clipboardDemo', 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: 'externalLink', icon: 'link' }
+ }
+ ]
+ },
+
+ { path: '*', redirect: '/404', hidden: true }
+]
diff --git a/vue/mock/user.js b/vue/mock/user.js
new file mode 100644
index 0000000..882c1f8
--- /dev/null
+++ b/vue/mock/user.js
@@ -0,0 +1,152 @@
+
+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'
+ }
+}
+
+export default [
+ // 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'
+ }
+ }
+ },
+ {
+ url: '/vue-element-admin/getMenu',
+ type: 'get',
+ response: _ => {
+ return {
+ "code": 20000,
+ "data": {
+ "menuList": [
+ {
+ 'create_time':'2018-03-16 11:33:00',
+ "menu_type": "M",
+ "path":'/projectManagement',
+ "component": "Layout",
+ "children": [
+ {
+ "create_time": "2018-03-16 11:33:00",
+ "menu_type": "C",
+ "children": [],
+ "parent_id": 1,
+ "menu_name": "客户管理",
+ "icon": "#",
+ "perms": "customer:index",
+ "order_num": 1,
+ "menu_id": 4,
+ "url": "/customer/index",
+ "path":'index',
+ "name": 'customer',
+ "component": "customer/index",
+ // "roles":"abpvnext_master.Customer"
+ "roles":"AbpIdentity.Users"
+ },
+ {
+ "create_time": "2018-03-16 11:33:00",
+ "menu_type": "C",
+ "children": [],
+ "parent_id": 1,
+ "menu_name": "合同管理",
+ "icon": "#",
+ "perms": "customer:contract",
+ "order_num": 1,
+ "menu_id": 4,
+ "url": "/customer/contract",
+ "path": 'contract',
+ "name": 'contract',
+ "component": "customer/contract",
+ // "roles": "abpvnext_master.Contract, abpvnext_master.Subject"
+ "roles":"AbpIdentity.Roles,AbpIdentity.Users"
+ }
+ ],
+ "parent_id": 0,
+ "menu_name": "系统管理",
+ "icon": "job",
+ "perms": "customer:index",
+ "order_num": 2,
+ "menu_id": 1,
+ "url": "#",
+ }
+ ],
+ "user": {
+ "login_name": "admin",
+ "user_id": 1,
+ "user_name": "管理员",
+ "dept_id": 1
+ }
+ }
+ }
+ }
+ }
+]
diff --git a/vue/mock/ux.js b/vue/mock/ux.js
new file mode 100644
index 0000000..1814647
--- /dev/null
+++ b/vue/mock/ux.js
@@ -0,0 +1,136 @@
+import Mock from 'mockjs'
+//表格字段数据
+const ListField = [{"fieldId":1,"formType":"text","fieldName":"leadsName","name":"线索名称","width":100,"type":1,"setting":[]},{"fieldId":2,"formType":"select","fieldName":"线索来源","name":"线索来源","width":100,"type":3},{"fieldId":3,"formType":"text","fieldName":"telephone","name":"电话","width":100,"type":1,"setting":[]},{"fieldId":4,"formType":"mobile","fieldName":"mobile","name":"手机","width":100,"type":7,"setting":[]},{"fieldId":5,"formType":"select","fieldName":"客户行业","name":"客户行业","width":100,"type":3},{"fieldId":6,"formType":"select","fieldName":"客户级别","name":"客户级别","width":100,"type":3},{"fieldId":7,"formType":"text","fieldName":"address","name":"地址","width":100,"type":1,"setting":[]},{"fieldId":8,"formType":"datetime","fieldName":"nextTime","name":"下次联系时间","width":100,"type":13,"setting":[]},{"fieldId":9,"formType":"text","fieldName":"remark","name":"备注","width":100,"type":1,"setting":[]},{"fieldId":null,"formType":"text","fieldName":"lastContent","name":"最后跟进记录","width":100,"type":1,"setting":[]},{"fieldId":null,"formType":"date","fieldName":"updateTime","name":"更新时间","width":100,"type":4,"setting":[]},{"fieldId":null,"formType":"date","fieldName":"createTime","name":"创建时间","width":100,"type":4,"setting":[]},{"fieldId":null,"formType":"text","fieldName":"ownerUserName","name":"负责人","width":100,"type":1,"setting":[]},{"fieldId":null,"formType":"text","fieldName":"createUserName","name":"创建人","width":100,"type":1,"setting":[]}]
+//表格list数据
+const List=[{"createUserId":3,"ownerUserName":"admin","address":"","createTime":"2020-11-10 10:05:32","createUserName":"admin","ownerUserId":3,"batchId":"3f9e3f45400f452a988bd466a5a36561","mobile":"","telephone":"","remark":"","客户行业":"IT","fieldBatchId":"3f9e3f45400f452a988bd466a5a36561","线索来源":"促销","isTransform":0,"lastContent":null,"followup":null,"leadsId":2,"updateTime":"2020-11-10 10:05:32","nextTime":"2020-11-12 00:00:00","leadsName":"77","customerId":null,"客户级别":"A(重点客户)"},{"createUserId":3,"ownerUserName":"admin","address":"","createTime":"2020-10-13 16:08:48","createUserName":"admin","ownerUserId":3,"batchId":"215f6dfc0b544a84b3b095d505bb62b8","mobile":"1336544343","telephone":"i","remark":"","客户行业":"","fieldBatchId":"215f6dfc0b544a84b3b095d505bb62b8","线索来源":"搜索引擎","isTransform":0,"lastContent":null,"followup":null,"leadsId":1,"updateTime":"2020-10-13 16:08:48","nextTime":null,"leadsName":"ii","customerId":null,"客户级别":"A(重点客户)"}]
+//detail 数据
+
+//record 数据
+ const recordList= [{"recordId":2,"img":[],"file":[],"createTime":"2020-11-11 14:06:31","nextTime":"2020-11-23 00:00:00","batchId":null,"category":"上门拜访","userImg":"","content":"77","realname":"admin"}]
+
+//基本信息
+const baseInfoListOne=[{"formType":"text","name":"线索名称","value":"ii"},{"formType":"text","name":"电话","value":"i"},{"formType":"mobile","name":"手机","value":"1336544343"},{"formType":"text","name":"地址","value":""},{"formType":"datetime","name":"下次联系时间","value":"2020-11-09 00:00:00"},{"formType":"text","name":"备注","value":""},{"formType":"select","name":"线索来源","value":"搜索引擎"},{"formType":"select","name":"客户行业","value":""},{"formType":"select","name":"客户级别","value":"A(重点客户)"}]
+const baseInfoListTwo=[{"formType":"text","name":"线索名称","value":"77"},{"formType":"text","name":"电话","value":""},{"formType":"mobile","name":"手机","value":""},{"formType":"text","name":"地址","value":""},{"formType":"datetime","name":"下次联系时间","value":"2020-11-23 00:00:00"},{"formType":"text","name":"备注","value":""},{"formType":"select","name":"线索来源","value":"促销"},{"formType":"select","name":"客户行业","value":"IT"},{"formType":"select","name":"客户级别","value":"A(重点客户)"}]
+
+const scenList=[{"formType":"text","fieldName":"leads_name","name":"线索名称","setting":[]},{"formType":"text","fieldName":"telephone","name":"电话","setting":[]},{"formType":"mobile","fieldName":"mobile","name":"手机","setting":[]},{"formType":"text","fieldName":"address","name":"地址","setting":[]},{"formType":"datetime","fieldName":"next_time","name":"下次联系时间","setting":[]},{"formType":"text","fieldName":"remark","name":"备注","setting":[]},{"formType":"user","fieldName":"owner_user_id","name":"负责人","setting":[]},{"formType":"user","fieldName":"create_user_id","name":"创建人","setting":[]},{"formType":"datetime","fieldName":"update_time","name":"更新时间","setting":[]},{"formType":"datetime","fieldName":"create_time","name":"创建时间","setting":[]},{"fieldId":2,"formType":"select","name":"线索来源","options":"促销,搜索引擎,广告,转介绍,线上注册,线上询价,预约上门,电话咨询,邮件咨询","type":3,"fieldName":"线索来源","setting":["促销","搜索引擎","广告","转介绍","线上注册","线上询价","预约上门","电话咨询","邮件咨询"]},{"fieldId":5,"formType":"select","name":"客户行业","options":"IT,金融业,房地产,商业服务,运输/物流,生产,政府,文化传媒","type":3,"fieldName":"客户行业","setting":["IT","金融业","房地产","商业服务","运输/物流","生产","政府","文化传媒"]},{"fieldId":6,"formType":"select","name":"客户级别","options":"A(重点客户),B(普通客户),C(非优先客户)","type":3,"fieldName":"客户级别977","setting":["A(重点客户)","B(普通客户)","C(非优先客户)"]}]
+export default [
+ {
+ url: '/vue-element-admin/ux/queryField',
+ type: 'get',
+ response: _ => {
+ return {
+ "code": 20000,
+ "data": ListField
+ }
+ }
+ },
+ {
+ url: '/vue-element-admin/ux/queryPageList',
+ 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: {
+ totalRow: mockList.length,
+ list: pageList
+ }
+ }
+ }
+ },
+ {
+ url: '/vue-element-admin/ux/detail',
+ type: 'get',
+ response: config => {
+ const { id } = config.query
+ for (const article of List) {
+ if (article.leadsId == id) {
+ return {
+ code: 20000,
+ data: article
+ }
+ }
+ }
+ }
+ },
+ {
+ url: '/vue-element-admin/ux/queryRecordOptions',
+ type: 'get',
+ response: _ => {
+ return {
+ "code": 20000,
+ "data":["打电话","发短信","上门拜访"]
+ }
+ }
+ },
+ {
+ url: '/vue-element-admin/ux/getRecord',
+ type: 'get',
+ response: config => {
+ const { page, limit, leadsId } = config.query
+ let mockList = recordList.filter(item => {
+ return true
+ })
+ const pageList = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1))
+
+ for (const item of recordList) {
+ if (item.recordId == leadsId) {
+ return {
+ code: 20000,
+ data: recordList
+ }
+ }else{
+ return {
+ code: 20000,
+ data: []
+ }
+ }
+ }
+ }
+ },
+ {
+ url: '/vue-element-admin/ux/information',
+ type: 'get',
+ response: config => {
+ const { types, id } = config.query
+ console.log(id)
+ if(id==1){
+ return {
+ code: 20000,
+ data: baseInfoListOne
+ }
+ }else{
+ return {
+ code: 20000,
+ data: baseInfoListTwo
+ }
+ }
+ }
+ },
+ {
+ url: '/vue-element-admin/ux/scene/queryField',
+ type: 'get',
+ response: _ => {
+ return {
+ "code": 20000,
+ "data":scenList
+ }
+ }
+ },
+
+]
+
diff --git a/vue/package.json b/vue/package.json
new file mode 100644
index 0000000..b6962fd
--- /dev/null
+++ b/vue/package.json
@@ -0,0 +1,133 @@
+{
+ "name": "vue-element-admin",
+ "version": "4.2.1",
+ "description": "A magical vue admin. An out-of-box UI solution for enterprise applications. Newest development stack of vue. Lots of awesome features",
+ "author": "Pan ",
+ "license": "MIT",
+ "scripts": {
+ "dev": "vue-cli-service serve",
+ "build:prod": "vue-cli-service build",
+ "build:stage": "vue-cli-service build --mode staging",
+ "preview": "node build/index.js --preview",
+ "lint": "eslint --ext .js,.vue src",
+ "test:unit": "jest --clearCache && vue-cli-service test:unit",
+ "test:ci": "npm run lint && npm run test:unit",
+ "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
+ "new": "plop"
+ },
+ "husky": {
+ "hooks": {
+ "pre-commit": "lint-staged"
+ }
+ },
+ "lint-staged": {
+ "src/**/*.{js,vue}": [
+ "eslint --fix",
+ "git add"
+ ]
+ },
+ "keywords": [
+ "vue",
+ "admin",
+ "dashboard",
+ "element-ui",
+ "boilerplate",
+ "admin-template",
+ "management-system"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/PanJiaChen/vue-element-admin.git"
+ },
+ "bugs": {
+ "url": "https://github.com/PanJiaChen/vue-element-admin/issues"
+ },
+ "dependencies": {
+ "@babel/polyfill": "^7.12.1",
+ "@riophae/vue-treeselect": "^0.4.0",
+ "axios": "0.18.1",
+ "babel-polyfill": "^6.26.0",
+ "clipboard": "2.0.4",
+ "codemirror": "5.45.0",
+ "driver.js": "0.9.5",
+ "dropzone": "5.5.1",
+ "echarts": "4.2.1",
+ "el-table-transfer": "^0.1.4",
+ "element-ui": "2.13.0",
+ "file-saver": "2.0.1",
+ "fuse.js": "3.4.4",
+ "js-cookie": "2.2.0",
+ "jsonlint": "1.6.3",
+ "jszip": "3.2.1",
+ "lockr": "^0.8.5",
+ "moment": "^2.29.1",
+ "normalize.css": "^7.0.0",
+ "nprogress": "0.2.0",
+ "path-to-regexp": "2.4.0",
+ "pinyin": "2.9.0",
+ "screenfull": "4.2.0",
+ "showdown": "^1.9.1",
+ "sortablejs": "1.8.4",
+ "tui-editor": "1.3.3",
+ "v-distpicker": "^1.2.7",
+ "vue": "2.6.10",
+ "vue-bus": "^1.2.1",
+ "vue-count-to": "1.0.13",
+ "vue-cropper": "^0.5.8",
+ "vue-i18n": "7.3.2",
+ "vue-infinite-scroll": "^2.0.2",
+ "vue-lazyload": "^1.3.3",
+ "vue-loader": "^15.9.5",
+ "vue-router": "3.0.2",
+ "vue-splitpane": "1.0.4",
+ "vuedraggable": "^2.24.3",
+ "vuex": "3.1.0",
+ "xlsx": "0.14.1"
+ },
+ "devDependencies": {
+ "@babel/core": "7.0.0",
+ "@babel/register": "7.0.0",
+ "@vue/cli-plugin-babel": "3.5.3",
+ "@vue/cli-plugin-eslint": "^3.9.1",
+ "@vue/cli-plugin-unit-jest": "^4.5.15",
+ "@vue/cli-service": "^4.5.15",
+ "@vue/test-utils": "1.0.0-beta.29",
+ "autoprefixer": "^9.8.8",
+ "babel-core": "7.0.0-bridge.0",
+ "babel-eslint": "10.0.1",
+ "babel-jest": "^26.6.3",
+ "chalk": "2.4.2",
+ "chokidar": "2.1.5",
+ "connect": "3.6.6",
+ "eslint": "5.15.3",
+ "eslint-plugin-vue": "5.2.2",
+ "html-webpack-plugin": "3.2.0",
+ "husky": "1.3.1",
+ "lint-staged": "8.1.5",
+ "mini-css-extract-plugin": "^2.4.6",
+ "mockjs": "1.0.1-beta3",
+ "node-sass": "^6.0.1",
+ "plop": "2.3.0",
+ "postcss-loader": "^4.0.4",
+ "postcss-px-to-viewport": "^1.1.1",
+ "runjs": "^4.3.2",
+ "sass-loader": "^10.0.1",
+ "script-ext-html-webpack-plugin": "2.1.3",
+ "script-loader": "0.7.2",
+ "serve-static": "^1.14.2",
+ "svg-sprite-loader": "4.1.3",
+ "svgo": "1.2.0",
+ "vue-happy-scroll": "^2.1.1",
+ "vue-template-compiler": "2.6.10",
+ "webpack": "^4.46.0",
+ "webpack-cli": "^4.9.1"
+ },
+ "engines": {
+ "node": ">=8.9",
+ "npm": ">= 3.0.0"
+ },
+ "browserslist": [
+ "> 1%",
+ "last 2 versions"
+ ]
+}
diff --git a/vue/plop-templates/component/index.hbs b/vue/plop-templates/component/index.hbs
new file mode 100644
index 0000000..7661055
--- /dev/null
+++ b/vue/plop-templates/component/index.hbs
@@ -0,0 +1,26 @@
+{{#if template}}
+
+
+
+{{/if}}
+
+{{#if script}}
+
+{{/if}}
+
+{{#if style}}
+
+{{/if}}
diff --git a/vue/plop-templates/component/prompt.js b/vue/plop-templates/component/prompt.js
new file mode 100644
index 0000000..3723e8e
--- /dev/null
+++ b/vue/plop-templates/component/prompt.js
@@ -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: '',
+ value: 'template',
+ checked: true
+ },
+ {
+ name: '
+{{/if}}
+
+{{#if style}}
+
+{{/if}}
diff --git a/vue/plop-templates/view/prompt.js b/vue/plop-templates/view/prompt.js
new file mode 100644
index 0000000..1d490ee
--- /dev/null
+++ b/vue/plop-templates/view/prompt.js
@@ -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: '',
+ value: 'template',
+ checked: true
+ },
+ {
+ name: ' -->
+
+
+
+
+
+
+