├── .gitignore
├── README.md
├── babel.config.js
├── package-lock.json
├── package.json
├── public
├── favicon.ico
└── index.html
├── src
├── App.vue
├── antdUse.js
├── api
│ └── report.js
├── app.less
├── assets
│ └── logo.png
├── components
│ ├── batchInput
│ │ └── index.vue
│ ├── c-menu
│ │ └── index.vue
│ ├── c-modal
│ │ └── index.vue
│ ├── c-table
│ │ └── index.vue
│ ├── editModel
│ │ └── index.vue
│ ├── largeSelect
│ │ └── index.vue
│ ├── largeTable
│ │ └── index.vue
│ └── searchModel
│ │ └── index.vue
├── layouts
│ ├── basicLayout.vue
│ └── pageLayout.vue
├── main.js
├── router
│ ├── README.md
│ ├── index.js
│ └── menu.js
├── store
│ ├── index.js
│ └── modules
│ │ └── app.js
├── utils
│ ├── exportExcel.js
│ ├── request.js
│ └── util.js
└── views
│ ├── login.vue
│ ├── report.vue
│ ├── role.vue
│ └── user.vue
├── vue.config.js
├── 便签.html
├── 安装记录.html
└── 涉及的vue3.0的升级.html
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 |
6 | # local env files
7 | .env.local
8 | .env.*.local
9 |
10 | # Log files
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 | pnpm-debug.log*
15 |
16 | # Editor directories and files
17 | .idea
18 | .vscode
19 | *.suo
20 | *.ntvs*
21 | *.njsproj
22 | *.sln
23 | *.sw?
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue-cli3 一个vue3.0的自定义脚手架
2 |
3 | ### 包含 路由懒加载、vuex、axios及其token校验、菜单及按钮级权限控制、开发环境服务转发配置、公共组件库、
4 | ### 登录登出、antd、less全局文件配置 等功能
5 |
6 | ### 目录结构
7 | dist 打包后文件
8 | public 静态文件
9 | src 根目录
10 | --api 接口
11 | --assets 图片、字体、文件等资源
12 | --components 公共组件
13 | --constants 公共常量
14 | --layouts 布局
15 | --router 路由
16 | --store vuex
17 | --utils 公共方法
18 | --views 页面
19 | package.json 包配置文件
20 | vue.config.js 开发环境服务配置文件
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ],
5 | plugins: [
6 | ["import", { "libraryName": "ant-design-vue", "libraryDirectory": "es", "style": true }],
7 | "@vue/babel-plugin-jsx"
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hello-vue3",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint"
9 | },
10 | "dependencies": {
11 | "@ant-design/icons-vue": "^6.0.1",
12 | "ant-design-vue": "^2.2.8",
13 | "axios": "^0.24.0",
14 | "core-js": "^3.6.5",
15 | "dayjs": "^1.10.7",
16 | "less": "^4.1.2",
17 | "less-loader": "^4.1.0",
18 | "moment": "^2.29.1",
19 | "vue": "^3.0.0",
20 | "vue-router": "^4.0.12",
21 | "vuex": "^4.0.2",
22 | "xlsx": "^0.17.3"
23 | },
24 | "devDependencies": {
25 | "@vue/cli-plugin-babel": "~4.5.0",
26 | "@vue/cli-plugin-eslint": "~4.5.0",
27 | "@vue/cli-service": "~4.5.0",
28 | "@vue/compiler-sfc": "^3.0.0",
29 | "babel-eslint": "^10.1.0",
30 | "babel-plugin-import": "^1.13.3",
31 | "eslint": "^6.7.2",
32 | "eslint-plugin-vue": "^7.0.0",
33 | "style-resources-loader": "^1.4.1",
34 | "vue-cli-plugin-style-resources-loader": "^0.1.5"
35 | },
36 | "eslintConfig": {
37 | "root": true,
38 | "env": {
39 | "node": true
40 | },
41 | "extends": [
42 | "plugin:vue/vue3-essential",
43 | "eslint:recommended"
44 | ],
45 | "parserOptions": {
46 | "parser": "babel-eslint"
47 | },
48 | "rules": {}
49 | },
50 | "browserslist": [
51 | "> 1%",
52 | "last 2 versions",
53 | "not dead"
54 | ]
55 | }
56 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aaron-China/vue-cli3/b4b813ee36a90ed81be7e1c008592749d962d9b1/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%= htmlWebpackPlugin.options.title %>
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
22 |
23 |
65 |
--------------------------------------------------------------------------------
/src/antdUse.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /**
3 | * 按需加载需要的antd组件
4 | */
5 | import {
6 | Layout,
7 | Avatar,
8 | Input,
9 | InputNumber,
10 | Button,
11 | Radio,
12 | Checkbox,
13 | Select,
14 | Form,
15 | Row,
16 | Col,
17 | Modal,
18 | Table,
19 | Tabs,
20 | Dropdown,
21 | Breadcrumb,
22 | Spin,
23 | Menu,
24 | Drawer,
25 | Tooltip,
26 | Tag,
27 | Divider,
28 | DatePicker,
29 | TimePicker,
30 | Upload,
31 | Popconfirm,
32 | message,
33 | notification,
34 | configProvider,
35 | } from "ant-design-vue";
36 |
37 | const antdUse = (app) => {
38 | app.use(Layout);
39 | app.use(Avatar);
40 | app.use(Input);
41 | app.use(InputNumber);
42 | app.use(Button);
43 | app.use(Radio);
44 | app.use(Checkbox);
45 | app.use(Select);
46 | app.use(Form);
47 | app.use(Row);
48 | app.use(Col);
49 | app.use(Modal);
50 | app.use(Table);
51 | app.use(Tabs);
52 | app.use(Dropdown);
53 | app.use(Breadcrumb);
54 | app.use(Spin);
55 | app.use(Menu);
56 | app.use(Drawer);
57 | app.use(Tooltip);
58 | app.use(Tag);
59 | app.use(Divider);
60 | app.use(DatePicker);
61 | app.use(TimePicker);
62 | app.use(Upload);
63 | app.use(Popconfirm);
64 | app.use(configProvider);
65 |
66 | app.config.globalProperties.$message = message;
67 | app.config.globalProperties.$notification = notification;
68 | };
69 |
70 | export default antdUse;
71 |
--------------------------------------------------------------------------------
/src/api/report.js:
--------------------------------------------------------------------------------
1 | import { axios } from '@/utils/request'
2 |
3 | export function getList (d) {
4 | // return axios({
5 | // url: `/report`,
6 | // method: 'post',
7 | // data: d
8 | // })
9 | return new Promise(function(resolve, reject) {
10 | let list = [
11 | {id: 1, factoryNo: '001', factoryName: '华为', materialCode: '3Z668A', materialName: '钣金门', bomLevel: 2, version: 'N167', qty: 30},
12 | {id: 2, factoryNo: '002', factoryName: '谷歌', materialCode: '3Z228A', materialName: '玻璃门', bomLevel: 3, version: 'N167', qty: 150},
13 | {id: 3, factoryNo: '001', factoryName: '华为', materialCode: 'WS2452', materialName: '钣金门2', bomLevel: 1, version: 'N167', qty: 230},
14 | {id: 4, factoryNo: '002', factoryName: '谷歌', materialCode: '2Z838A', materialName: '散热器', bomLevel: 2, version: 'N167', qty: 76},
15 | {id: 5, factoryNo: '003', factoryName: '中芯国际', materialCode: 'QJ8623', materialName: '小J骨架', bomLevel: 2, version: 'N167', qty: 99},
16 | {id: 6, factoryNo: '004', factoryName: '宁德时代', materialCode: '255FE3', materialName: '小J面板', bomLevel: 1, version: 'N167', qty: 30},
17 | {id: 7, factoryNo: '004', factoryName: '宁德时代', materialCode: '90JY65', materialName: '支撑臂', bomLevel: 2, version: 'N167', qty: 52},
18 | {id: 8, factoryNo: '001', factoryName: '华为', materialCode: '74GER4', materialName: '冷凝器', bomLevel: 3, version: 'N167', qty: 16},
19 | ];
20 | if(d.factoryNo) {
21 | list = list.filter(item => item.factoryNo === d.factoryNo)
22 | }
23 | if(d.materialCode) {
24 | list = list.filter(item => item.materialCode.indexOf(d.materialCode) > -1 )
25 | }
26 | resolve({
27 | code: 200,
28 | records: list,
29 | current: 1,
30 | size: 20,
31 | total: 8
32 | })
33 | });
34 | }
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/app.less:
--------------------------------------------------------------------------------
1 | @normal: #3F66E0;
2 | @edit: #00C7B8;
3 | @rest: #FBA908;
4 | @delete: #EC2424;
5 | @other: #09BCE4;
6 | @edit: #00C7B8;
7 | @active: #00f6f0;
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aaron-China/vue-cli3/b4b813ee36a90ed81be7e1c008592749d962d9b1/src/assets/logo.png
--------------------------------------------------------------------------------
/src/components/batchInput/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
26 |
27 |
28 |
105 |
--------------------------------------------------------------------------------
/src/components/c-menu/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
47 |
48 |
49 |
144 |
145 |
203 |
--------------------------------------------------------------------------------
/src/components/c-modal/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 |
64 |
--------------------------------------------------------------------------------
/src/components/c-table/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
15 |
16 |
共 {{total}} 条数据
17 |
18 |
19 |
20 |
113 |
114 |
140 |
--------------------------------------------------------------------------------
/src/components/editModel/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
17 |
18 |
24 |
28 | item.needBack && handleBack(e.target.value, item.key)"
35 | />
36 |
37 | item.needBack && handleBack(e.target.value, item.key)"
46 | />
47 |
48 | item.needBack && handleBack(e, item.key)"
64 | >
65 |
71 | {{ optionItem.label }}
72 |
73 |
74 |
75 | handleCustomChange(v, item)"
83 | />
84 |
85 | handleCustomChange(e.target.value, item)"
91 | />
92 |
93 | item.needBack && handleBack(e, item.key)"
102 | />
103 |
104 | item.needBack && handleBack(e, item.key)"
115 | >
116 |
117 |
118 | item.needBack && handleBack(e, item.key)"
123 | >
124 |
129 | {{ optionItem.label }}
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 | 取消
140 |
141 |
142 | 确定
143 |
144 |
145 |
146 |
147 |
148 |
261 |
262 |
263 |
--------------------------------------------------------------------------------
/src/components/largeSelect/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
18 |
19 | {{op.label}}
20 |
21 |
22 |
25 |
26 |
27 |
28 |
170 |
171 |
190 |
--------------------------------------------------------------------------------
/src/components/largeTable/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
14 |
17 |
共 {{total}} 条数据
18 |
19 |
20 |
21 |
209 |
210 |
259 |
--------------------------------------------------------------------------------
/src/components/searchModel/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 |
17 | item.needBack && handleBack(e.target.value, item.key)"
22 | />
23 |
24 |
25 |
30 | item.needBack && handleBack(e.target.value, item.key)"
37 | />
38 |
39 |
40 |
45 | item.needBack && handleBack(e, item.key)"
59 | >
60 | {{ optionItem.label }}
66 |
67 |
68 |
69 |
74 | handleCustomChange(v, item)"
80 | />
81 |
82 |
83 |
88 | handleCustomChange(e.target.value, item)"
93 | />
94 |
95 |
96 |
101 | item.needBack && handleBack(e, item.key)"
109 | />
110 |
111 |
112 |
117 | item.needBack && handleBack(e, item.key)"
125 | />
126 |
127 |
128 |
132 | item.needBack && handleBack(e.target.value, item.key)"
136 | >{{item.label}}
137 |
138 |
139 |
145 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
266 |
267 |
281 |
--------------------------------------------------------------------------------
/src/layouts/basicLayout.vue:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 |
33 |
123 |
124 |
153 |
--------------------------------------------------------------------------------
/src/layouts/pageLayout.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
17 |
18 |
20 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import dayjs from 'dayjs'
3 | import App from './App.vue'
4 | import './antdUse'
5 | import router from './router'
6 | import store from './store'
7 | import antdUse from './antdUse'
8 | import 'dayjs/locale/zh-cn';
9 | import './app.less'
10 |
11 | // 创建应用上下文
12 | const app = createApp(App)
13 | app.config.productionTip
14 | dayjs.locale('zh-cn');
15 | // 原型上添加全局字段方式变了
16 | app.config.globalProperties.$dayjs = dayjs
17 | // 引入路由、vuex、 antd
18 | antdUse(app)
19 | app.use(router)
20 | app.use(store)
21 |
22 | // 挂载dom
23 | app.mount('#app')
24 |
25 |
--------------------------------------------------------------------------------
/src/router/README.md:
--------------------------------------------------------------------------------
1 | path String url地址
2 | name String 路由标识
3 | title String 标题
4 | hidden Boolean 是否显示在菜单中, 默认false 显示
5 | meta Object 一些额外参数,比如需要多语言、描述等等,结合需求设定
6 | redirect String 重定向地址
7 | children Array 子菜单
8 | component BOM 页面
9 |
10 | ```javascript
11 | export default new Router({
12 | mode: 'history',
13 | base: process.env.BASE_URL,
14 | scrollBehavior: () => ({ y: 0 }),
15 | routes: [
16 | {
17 | path: '/',
18 | name: 'main',
19 | hidden: true,
20 | title: 'main',
21 | meta: {
22 | international: 'home'
23 | },
24 | redirect: '/home',
25 | children: [
26 | {
27 | path: '/home',
28 | name: 'home',
29 | title: '首页',
30 | meta: {
31 | international: 'home'
32 | },
33 | // 懒加载
34 | component: () => import('@views/home.vue')
35 | },
36 | ]
37 | }
38 | ]
39 | })
40 | ```
41 |
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import { createRouter, createWebHistory } from 'vue-router'
2 | import { ROUTE } from './menu.js'
3 |
4 | const route = createRouter({
5 | history: createWebHistory(process.env.BASE_URL),
6 | scrollBehavior: () => ({ y: 0 }),
7 | routes: ROUTE
8 | })
9 |
10 | export default route
11 |
--------------------------------------------------------------------------------
/src/router/menu.js:
--------------------------------------------------------------------------------
1 | import BasicLayout from '@layouts/basicLayout'
2 | import PageLayout from '@layouts/pageLayout'
3 | export const ROUTE = [
4 | {
5 | path: '/',
6 | name: 'main',
7 | redirect: '/report',
8 | component: BasicLayout,
9 | children: [
10 | {
11 | path: '/report',
12 | name: 'report',
13 | title: '报表中心',
14 | component: () => import('@views/report.vue')
15 | },
16 | {
17 | path: '/setting',
18 | name: 'setting',
19 | title: '配置中心',
20 | component: PageLayout,
21 | redirect: '/setting/user',
22 | children: [
23 | {
24 | path: '/setting/user',
25 | name: 'user',
26 | title: '用户管理',
27 | component: PageLayout,
28 | redirect: '/setting/user/add',
29 | children: [
30 | {
31 | path: '/setting/user/add',
32 | name: 'add',
33 | title: '增加',
34 | component: () => import('@views/user.vue')
35 | },
36 | {
37 | path: '/setting/user/edit',
38 | name: 'edit',
39 | title: '修改',
40 | component: () => import('@views/user.vue')
41 | },
42 | {
43 | path: '/setting/user/delete',
44 | name: 'delete',
45 | title: '删除',
46 | component: () => import('@views/user.vue')
47 | },
48 | ]
49 | },
50 | {
51 | path: '/setting/role',
52 | name: 'role',
53 | title: '角色管理',
54 | component: () => import('@views/role.vue')
55 | }
56 | ]
57 | }
58 | ]
59 | },
60 | {
61 | path: '/login',
62 | name: 'login',
63 | title: '登陆',
64 | hidden: true,
65 | component: () => import('@views/login.vue')
66 | },
67 | {
68 | path: '/:catchAll(.*)',
69 | redirect: '/404',
70 | hidden: true
71 | }
72 | ]
73 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import { createStore } from 'vuex'
2 | import app from './modules/app.js'
3 |
4 | const store = createStore({
5 | modules: {
6 | app
7 | },
8 | state: () => ({}),
9 | mutations: {},
10 | actions: {},
11 | getters: {}
12 | })
13 | export default store
--------------------------------------------------------------------------------
/src/store/modules/app.js:
--------------------------------------------------------------------------------
1 | const app = {
2 | namespaced: 'app',
3 | state: () => ({
4 | token: '3mnuehn457873nberuwen',
5 | user: {},
6 | factoryList: [
7 | {value: '001', label: '华为'},
8 | {value: '002', label: '谷歌'},
9 | {value: '003', label: '中芯国际'},
10 | {value: '004', label: '宁德时代'}
11 | ],
12 | // 所有权限. type 类型 区分菜单和按钮 path权限所在的菜单路径 key 是权限关键字,按钮才有
13 | permission: [],
14 | auth: {}, // 按钮权限
15 | }),
16 | mutations: {
17 | setToken: (state, d) => {
18 | state.token = d
19 | },
20 | setUser: (state, d) => {
21 | state.user = d.user
22 | state.permission = d.permission
23 | state.auth = d.auth
24 | }
25 | },
26 | actions: {}
27 | }
28 | export default app
--------------------------------------------------------------------------------
/src/utils/exportExcel.js:
--------------------------------------------------------------------------------
1 | import XLSX from 'xlsx';
2 |
3 | /*
4 | 备注:直接传入表格的 columns 和 data即可
5 |
6 | header: [{dataIndex: 'site', title: '地点'}] string Array 标题
7 | body: [{time: '3点', site: '青岛'}] object Array 数据
8 | name: '数据导出' string 文件名
9 | */
10 | export function expoerExcel(header = [], body = [], name = '') {
11 | // 处理标题
12 | const dataSource = [], r1 = [];
13 | header.forEach(item => {
14 | r1.push(item.title)
15 | })
16 | dataSource.push(r1)
17 |
18 | // 处理数据
19 | body.forEach(b => {
20 | let r = [];
21 | header.forEach(h => {
22 | r.push(b[h.dataIndex])
23 | })
24 | dataSource.push(r)
25 | })
26 |
27 | const worksheet = XLSX.utils.aoa_to_sheet(dataSource);
28 | const new_workbook = XLSX.utils.book_new();
29 | XLSX.utils.book_append_sheet(new_workbook, worksheet, 'sheet1');
30 | XLSX.writeFile(new_workbook, `${name || '导出报表'}.xlsx`);
31 | }
--------------------------------------------------------------------------------
/src/utils/request.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import router from '@router/index.js'
3 | import store from '@store/index.js'
4 | import notification from 'ant-design-vue/es/notification'
5 |
6 | // 创建 axios 实例
7 | const service = axios.create({
8 | baseURL: '/', // api base_url
9 | withCredentials: true,
10 | timeout: 60000, // 超时时间:6分钟 注意和nginx配置保持一致
11 | maxBodyLength: 31457280, // 请求体最大长度 单位B,上限30MB 注意和nginx配置保持一致
12 | maxContentLength: 5242880, // 响应的最大长度,单位 B ,5MB,针对文件或者表格数据大量返回 注意和nginx配置保持一致
13 | })
14 |
15 | const err = (error) => {
16 | if (error.response) {
17 | const data = error.response.data
18 | if (error.response.status === 401) { // 登录失效
19 | router.push({path: '/login'})
20 | } else if (error.response.status === 402) { // 缺少权限
21 | notification.error({
22 | message: '您没有权限查看当前信息',
23 | description: '请联系管理员获取数据权限',
24 | duration: null
25 | })
26 | } else if (error.response.status === 403) {
27 | notification.error({
28 | message: 'Forbidden',
29 | description: data.message
30 | })
31 | } else if (error.response.status === 504) { // 请求超时
32 | notification.error({
33 | message: '提示',
34 | description: '请求时间较长,请稍后查看',
35 | duration: null
36 | });
37 | }
38 | } else {
39 | // 请求超时
40 | notification.error({
41 | message: '提示',
42 | description: '请求时间较长,请稍后查看',
43 | duration: null
44 | });
45 | }
46 | return Promise.reject(error)
47 | }
48 |
49 | // 请求拦截,设置token
50 | service.interceptors.request.use((config) => {
51 | config.headers['Access-Token'] = store.state.app.token || ''
52 | return config
53 | }, err)
54 |
55 | // 处理响应
56 | service.interceptors.response.use((response) => {
57 | return response.data
58 | }, err)
59 |
60 | function requests(options = {}) {
61 | return service.request({ ...options })
62 | }
63 |
64 | export { requests as axios }
65 |
--------------------------------------------------------------------------------
/src/utils/util.js:
--------------------------------------------------------------------------------
1 | // 遍历路由,获取左侧主菜单, 精简字段,并按照权限过滤
2 | export const filterMenu = (l, p) => {
3 | let arr = [];
4 | for(let i = 0; i < l.length; i++) {
5 | // 校验权限,权限存储底层路由即可,父级菜单自动通过
6 | let able = p.some(item => item.path.indexOf(l[i].path) === 0)
7 | if (!l[i].hidden && able) {
8 | let obj = {...l[i]};
9 | delete obj.component
10 | if (l[i].children && l[i].children.length) {
11 | obj.children = filterMenu(l[i].children, p)
12 | }
13 | arr.push(obj)
14 | }
15 | }
16 | return arr
17 | }
18 |
19 | // url传参,处理参数
20 | export function makeQuery (obj = {}) {
21 | let arr = [], str = '';
22 | for (let key in obj) {
23 | if (obj[key] || obj[key] === 0 || obj[key] === false) {
24 | arr.push(`${key}=${obj[key]}`)
25 | }
26 | }
27 | str = arr.join('&')
28 | return str ? `?${str}` : ''
29 | }
30 |
31 | // 表单自定义校验,校验长度
32 | export function checklength(_, value) {
33 | if (value) {
34 | const arr = value.split(',')
35 | if (arr.length > 500) {
36 | return Promise.reject(new Error('最大支持500条数据'));
37 | } else {
38 | return Promise.resolve();
39 | }
40 | } else {
41 | return Promise.resolve();
42 | }
43 | }
44 | // 表单自定义校验,校验重复性
45 | export function checkRepeat (_, value) {
46 | if (value) {
47 | const arr = value.split(',')
48 | if ((new Set(arr)).size != arr.length) {
49 | return Promise.reject(new Error('存在重复信息'));
50 | } else {
51 | return Promise.resolve();
52 | }
53 | } else {
54 | return Promise.resolve();
55 | }
56 | }
--------------------------------------------------------------------------------
/src/views/login.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
16 |
17 |
18 |
22 |
23 |
26 |
27 |
28 |
29 |
30 |
31 |
98 |
99 |
125 |
--------------------------------------------------------------------------------
/src/views/report.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 新增
7 | 批量删除
8 | 导出
9 |
10 |
11 |
22 |
23 |
24 |
33 |
34 |
35 |
36 |
37 |
248 |
250 |
--------------------------------------------------------------------------------
/src/views/role.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
15 |
16 |
21 |
22 |
23 |
24 |
100 |
101 |
103 |
--------------------------------------------------------------------------------
/src/views/user.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | 配置中心
4 |
5 |
6 |
7 |
19 |
20 |
22 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const webpack = require('webpack')
3 | function resolve (dir) {
4 | return path.join(__dirname, dir)
5 | }
6 |
7 | // https://cli.vuejs.org/zh/config/#css-loaderoptions
8 | module.exports = {
9 | pluginOptions: {
10 | 'style-resources-loader': {
11 | preProcessor: 'less',
12 | patterns: [path.resolve(__dirname, "src/app.less")] // 引入全局样式变量
13 | }
14 | },
15 | css: {
16 | loaderOptions: {
17 | less: {
18 | javascriptEnabled: true
19 | }
20 | }
21 | },
22 | chainWebpack: (config) => {
23 | config.resolve.alias
24 | .set('@', resolve('src'))
25 | .set('@api', resolve('src/api'))
26 | .set('@assets', resolve('src/assets'))
27 | .set('@layouts', resolve('src/layouts'))
28 | .set('@static', resolve('src/static'))
29 | .set('@components', resolve('src/components'))
30 | .set('@router', resolve('src/router'))
31 | .set('@utils', resolve('src/utils'))
32 | .set('@store', resolve('src/store'))
33 | .set('@views', resolve('src/views'))
34 | },
35 | // 服务转发
36 | devServer: {
37 | port: 8003,
38 | proxy: {
39 | '/WebSocketConfig/': {
40 | target: 'ws://test.com',
41 | changeOrigin: true,
42 | ws: true, // 开启sockjs
43 | },
44 | '/api/': {
45 | target: 'http://test.com',
46 | changeOrigin: true,
47 | ws: false, // 关闭sockjs
48 | },
49 | },
50 | },
51 |
52 | // disable source map in production
53 | productionSourceMap: false,
54 | lintOnSave: false,
55 | // babel-loader no-ignore node_modules/*
56 | transpileDependencies: [],
57 | }
58 |
--------------------------------------------------------------------------------
/便签.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 | vue-cli地址
11 | vue-cli3地址
12 |
136 |
137 |
--------------------------------------------------------------------------------
/安装记录.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 |
35 |
36 |
--------------------------------------------------------------------------------
/涉及的vue3.0的升级.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 |
62 |
63 |
--------------------------------------------------------------------------------