Commit c1b532ad9ca4f9d04954c7dd1d1b601b43ff0440
1 parent
ae233dc9
权限配置,路由基础设置
Showing
50 changed files
with
3644 additions
and
0 deletions
src/api/apis/login.js
0 → 100644
src/api/apis/role.js
0 → 100644
1 | + | ||
2 | +import axios from "../axios" | ||
3 | +import roleUrls from "../urls/role" | ||
4 | + | ||
5 | +export default { | ||
6 | + // 获取权限列表 | ||
7 | + fetchGetRoleList () { | ||
8 | + return axios.post(roleUrls.getRoleList) | ||
9 | + }, | ||
10 | + // 增加角色 | ||
11 | + fetchAddRole (data) { | ||
12 | + return axios.post(roleUrls.addRole, data) | ||
13 | + }, | ||
14 | + // 删除角色 | ||
15 | + fetchDelRole (data) { | ||
16 | + return axios.post(roleUrls.delRole, data) | ||
17 | + }, | ||
18 | + // 分配角色权限 | ||
19 | + fetchRolePermissions (data) { | ||
20 | + return axios.post(roleUrls.rolePermissions, data) | ||
21 | + } | ||
22 | +} | ||
23 | + |
src/api/apis/user.js
0 → 100644
1 | + | ||
2 | +import axios from "../axios" | ||
3 | +import userUrls from "../urls/user" | ||
4 | + | ||
5 | +export default { | ||
6 | + // 注册/添加账号 | ||
7 | + fetchRegister (data) { | ||
8 | + return axios.post(userUrls.register, data) | ||
9 | + }, | ||
10 | + // 删除用户 | ||
11 | + fetchDelUser (data) { | ||
12 | + return axios.post(userUrls.delUser, data) | ||
13 | + }, | ||
14 | + // 获取用户列表 | ||
15 | + fetchUserList (data) { | ||
16 | + return axios.post(userUrls.userList, data) | ||
17 | + }, | ||
18 | + // 修改用户信息 | ||
19 | + fetchEditUser (data) { | ||
20 | + return axios.post(userUrls.editUser, data) | ||
21 | + }, | ||
22 | + // 获取当前用户信息 | ||
23 | + fetchGetUserInfo () { | ||
24 | + return axios.get(userUrls.getUserInfo) | ||
25 | + }, | ||
26 | + // 获取用户信息 | ||
27 | + fetchGetUserInfoId (data) { | ||
28 | + return axios.post(userUrls.getUserInfoId, data) | ||
29 | + }, | ||
30 | + // 修改密码 | ||
31 | + fetchEditPassword (data) { | ||
32 | + return axios.post(userUrls.editPassword, data) | ||
33 | + } | ||
34 | +} | ||
35 | + |
src/api/axios.js
0 → 100644
1 | +import axios from "axios" | ||
2 | +import Cookies from "js-cookie" | ||
3 | +import NProgress from "nprogress" | ||
4 | +import { Message } from "element-ui" | ||
5 | +// axios默认配置 | ||
6 | +axios.defaults.timeout = 10000 // 超时时间 | ||
7 | +axios.defaults.baseURL = process.env.API_HOST | ||
8 | + | ||
9 | +// http request 拦截器 | ||
10 | +axios.interceptors.request.use(config => { | ||
11 | + NProgress.start() | ||
12 | + config.headers["Content-Type"] = "application/json;charset=UTF-8" | ||
13 | + if (Cookies.get("access_token")) { | ||
14 | + config.headers.Authorization = "Bearer" + Cookies.get("access_token") | ||
15 | + } | ||
16 | + return config | ||
17 | +}, | ||
18 | +error => { | ||
19 | + return Promise.reject(error.response) | ||
20 | +}) | ||
21 | + | ||
22 | +// http response 拦截器 | ||
23 | +axios.interceptors.response.use( | ||
24 | + response => { | ||
25 | + NProgress.done() | ||
26 | + if (response.data.code === 11000) { | ||
27 | + Cookies.set("access_token", response.data.message, { expires: 1 / 12 }) | ||
28 | + return Promise.resolve() | ||
29 | + } else if (response.data.code === 10000) { // 约定报错信息 | ||
30 | + Message({ | ||
31 | + message: response.data.message, | ||
32 | + type: "warning" | ||
33 | + }) | ||
34 | + return Promise.reject(response) | ||
35 | + } else { | ||
36 | + return Promise.resolve(response) | ||
37 | + } | ||
38 | + }, | ||
39 | + error => { | ||
40 | + if (error.response.status === 404) { | ||
41 | + Message({ | ||
42 | + message: "请求地址出错", | ||
43 | + type: "warning" | ||
44 | + }) | ||
45 | + } else if (error.response.status === 401) { | ||
46 | + Message({ | ||
47 | + message: error.response.data.message, | ||
48 | + type: "warning" | ||
49 | + }) | ||
50 | + Cookies.remove("access_token") | ||
51 | + setTimeout(() => { | ||
52 | + location.reload() | ||
53 | + }, 3000) | ||
54 | + } | ||
55 | + return Promise.reject(error.response) // 返回接口返回的错误信息 | ||
56 | + }) | ||
57 | +export default axios |
src/api/index.js
0 → 100644
src/api/urls/login.js
0 → 100644
src/api/urls/role.js
0 → 100644
src/api/urls/user.js
0 → 100644
1 | + | ||
2 | +export default { | ||
3 | + // 注册/添加账号 | ||
4 | + register: "/admin/user/register", | ||
5 | + // 删除用户 | ||
6 | + delUser: "/user/delUser", | ||
7 | + // 修改用户信息 | ||
8 | + editUser: "/user/editUserInfo", | ||
9 | + // 获取当前用户信息 | ||
10 | + getUserInfo: "/user/getUserInfo", | ||
11 | + // 获取用户信息 | ||
12 | + getUserInfoId: "/user/getUserInfoId", | ||
13 | + // 获取用户列表 | ||
14 | + userList: "/user/userList", | ||
15 | + // 修改密码 | ||
16 | + editPassword: "/user/editPassword" | ||
17 | +} |
src/assets/images/chiken.png
0 → 100644
56.7 KB
src/assets/images/login-bg.png
0 → 100644
277 KB
src/assets/images/logo.png
0 → 100644
7.89 KB
src/assets/images/mandefault.png
0 → 100644
5.58 KB
src/assets/images/womandefault.png
0 → 100644
5.45 KB
src/assets/img404/bg404.jpg
0 → 100644
35.8 KB
src/assets/img404/i404.png
0 → 100644
16.8 KB
src/assets/img404/sign.png
0 → 100644
423 KB
src/assets/lang.png
0 → 100644
6.05 KB
src/components/ECharts/lineEcharts.vue
0 → 100644
1 | +<template> | ||
2 | + <div> | ||
3 | + <div :id="id" :style="{width: width, height: height}"></div> | ||
4 | + </div> | ||
5 | +</template> | ||
6 | + | ||
7 | +<script> | ||
8 | +import * as echarts from "echarts" | ||
9 | +export default { | ||
10 | + name: "lineEcharts", | ||
11 | + props: { | ||
12 | + id: { | ||
13 | + type: String, | ||
14 | + default: "myChart" | ||
15 | + }, | ||
16 | + width: { | ||
17 | + type: String, | ||
18 | + default: "100%" | ||
19 | + }, | ||
20 | + height: { | ||
21 | + type: String, | ||
22 | + default: "100%" | ||
23 | + } | ||
24 | + }, | ||
25 | + data () { | ||
26 | + return { | ||
27 | + chart: null | ||
28 | + } | ||
29 | + }, | ||
30 | + mounted () { | ||
31 | + this.initChart() | ||
32 | + }, | ||
33 | + methods: { | ||
34 | + initChart () { | ||
35 | + this.chart = echarts.init(document.getElementById(this.id)) | ||
36 | + | ||
37 | + this.chart.setOption({ | ||
38 | + title: { | ||
39 | + text: "折线图堆叠" | ||
40 | + }, | ||
41 | + tooltip: { | ||
42 | + trigger: "axis" | ||
43 | + }, | ||
44 | + legend: { | ||
45 | + data: ["邮件营销", "联盟广告", "视频广告", "直接访问", "搜索引擎"] | ||
46 | + }, | ||
47 | + grid: { | ||
48 | + left: "3%", | ||
49 | + right: "4%", | ||
50 | + bottom: "3%", | ||
51 | + containLabel: true | ||
52 | + }, | ||
53 | + toolbox: { | ||
54 | + feature: { | ||
55 | + saveAsImage: {} | ||
56 | + } | ||
57 | + }, | ||
58 | + xAxis: { | ||
59 | + type: "category", | ||
60 | + boundaryGap: false, | ||
61 | + data: ["周一", "周二", "周三", "周四", "周五", "周六", "周日"] | ||
62 | + }, | ||
63 | + yAxis: { | ||
64 | + type: "value" | ||
65 | + }, | ||
66 | + series: [ | ||
67 | + { | ||
68 | + name: "邮件营销", | ||
69 | + type: "line", | ||
70 | + stack: "总量", | ||
71 | + data: [8200, 6320, 5010, 4340, 3400, 2300, 1100] | ||
72 | + }, | ||
73 | + { | ||
74 | + name: "联盟广告", | ||
75 | + type: "line", | ||
76 | + stack: "总量", | ||
77 | + data: [2200, 3820, 1910, 2340, 4900, 3300, 1100] | ||
78 | + }, | ||
79 | + { | ||
80 | + name: "视频广告", | ||
81 | + type: "line", | ||
82 | + stack: "总量", | ||
83 | + data: [2500, 4302, 5010, 2540, 6900, 5300, 6410] | ||
84 | + }, | ||
85 | + { | ||
86 | + name: "直接访问", | ||
87 | + type: "line", | ||
88 | + stack: "总量", | ||
89 | + data: [5320, 7332, 9301, 6334, 5390, 4330, 1320] | ||
90 | + }, | ||
91 | + { | ||
92 | + name: "搜索引擎", | ||
93 | + type: "line", | ||
94 | + stack: "总量", | ||
95 | + data: [8820, 1932, 5901, 7304, 2900, 3300, 8200] | ||
96 | + } | ||
97 | + ] | ||
98 | + }) | ||
99 | + } | ||
100 | + } | ||
101 | +} | ||
102 | +</script> | ||
103 | + | ||
104 | +<style scoped> | ||
105 | + | ||
106 | +</style> |
src/components/lang/langSelect.vue
0 → 100644
1 | +<template> | ||
2 | + <el-dropdown class='international' @command="handleSetLanguage"> | ||
3 | + <div> | ||
4 | + <span class="el-dropdown-link"><i class="fa fa-language fa-lg"></i> {{language}}<i class="el-icon-arrow-down el-icon--right"></i> | ||
5 | + </span> | ||
6 | + </div> | ||
7 | + <el-dropdown-menu slot="dropdown"> | ||
8 | + <el-dropdown-item command="cn">中文</el-dropdown-item> | ||
9 | + <el-dropdown-item command="en">English</el-dropdown-item> | ||
10 | + </el-dropdown-menu> | ||
11 | + </el-dropdown> | ||
12 | +</template> | ||
13 | +<script> | ||
14 | +export default { | ||
15 | + name: "langSelect", | ||
16 | + data () { | ||
17 | + return { | ||
18 | + language: "" | ||
19 | + } | ||
20 | + }, | ||
21 | + mounted () { | ||
22 | + const _lang = localStorage.lang || "cn" | ||
23 | + this.getLanguage(_lang) | ||
24 | + }, | ||
25 | + methods: { | ||
26 | + handleSetLanguage (lang) { | ||
27 | + this.$i18n.locale = lang | ||
28 | + localStorage.setItem("lang", lang) | ||
29 | + this.getLanguage(lang) | ||
30 | + }, | ||
31 | + getLanguage (val) { | ||
32 | + if (val === "cn") { | ||
33 | + this.language = "中文" | ||
34 | + } | ||
35 | + if (val === "en") { | ||
36 | + this.language = "English" | ||
37 | + } | ||
38 | + } | ||
39 | + } | ||
40 | +} | ||
41 | +</script> | ||
42 | +<style> | ||
43 | + .international .el-dropdown-link { cursor: pointer; color: #666666; font-size: 14px; } | ||
44 | + .el-icon-arrow-down { font-size: 14px; } | ||
45 | +</style> | ||
46 | +<style scoped> | ||
47 | + .international-icon { | ||
48 | + font-size: 20px; | ||
49 | + cursor: pointer; | ||
50 | + vertical-align: -5px !important; | ||
51 | + } | ||
52 | +</style> | ||
53 | + |
src/components/userForm/editPassword.vue
0 → 100644
1 | +<template> | ||
2 | + <el-dialog title="修改密码" width="700px" :visible.sync="visible" destroy-on-close @close="closeCallback"> | ||
3 | + <div class="card"> | ||
4 | + <p class="title"><i class="fa fa-th-large fa-lg"></i>修改密码</p> | ||
5 | + <el-form :model="ruleForm2" status-icon :rules="rules2" ref="ruleForm2" label-width="100px" class="demo-ruleForm"> | ||
6 | + <el-form-item label="原密码" prop="oldPassword"> | ||
7 | + <el-input type="password" v-model="ruleForm2.oldPassword" autocomplete="off"></el-input> | ||
8 | + </el-form-item> | ||
9 | + <el-form-item label="密码" prop="password"> | ||
10 | + <el-input type="password" v-model="ruleForm2.password" autocomplete="off"></el-input> | ||
11 | + </el-form-item> | ||
12 | + <el-form-item label="确认密码" prop="checkPass"> | ||
13 | + <el-input type="password" v-model="ruleForm2.checkPass" autocomplete="off"></el-input> | ||
14 | + </el-form-item> | ||
15 | + <el-form-item> | ||
16 | + <el-button type="primary" @click="submitForm('ruleForm2')">提交</el-button> | ||
17 | + <el-button @click="resetForm('ruleForm2')">重置</el-button> | ||
18 | + </el-form-item> | ||
19 | + </el-form> | ||
20 | + </div> | ||
21 | + </el-dialog> | ||
22 | +</template> | ||
23 | + | ||
24 | +<script> | ||
25 | +import Cookies from "js-cookie" | ||
26 | +export default { | ||
27 | + name: "editPassword", | ||
28 | + props: { | ||
29 | + dialogVisible: { | ||
30 | + type: Boolean, | ||
31 | + default: false | ||
32 | + } | ||
33 | + }, | ||
34 | + data () { | ||
35 | + var validatePass = (rule, value, callback) => { | ||
36 | + if (value === "") { | ||
37 | + callback(new Error("请输入密码")) | ||
38 | + } else if (value.toString().length < 6) { | ||
39 | + callback(new Error("密码长度不能低于6位")) | ||
40 | + } else { | ||
41 | + if (this.ruleForm2.checkPass !== "") { | ||
42 | + this.$refs.ruleForm2.validateField("checkPass") | ||
43 | + } | ||
44 | + callback() | ||
45 | + } | ||
46 | + } | ||
47 | + var validatePass2 = (rule, value, callback) => { | ||
48 | + if (value === "") { | ||
49 | + callback(new Error("请再次输入密码")) | ||
50 | + } else if (value.toString().length < 6) { | ||
51 | + callback(new Error("密码长度不能低于6位")) | ||
52 | + } else if (value !== this.ruleForm2.password) { | ||
53 | + callback(new Error("两次输入密码不一致!")) | ||
54 | + } else { | ||
55 | + callback() | ||
56 | + } | ||
57 | + } | ||
58 | + return { | ||
59 | + visible: this.dialogVisible, | ||
60 | + ruleForm2: { | ||
61 | + oldPassword: "", | ||
62 | + password: "", | ||
63 | + checkPass: "" | ||
64 | + }, | ||
65 | + rules2: { | ||
66 | + oldPassword: [ | ||
67 | + {required: true, validator: validatePass, trigger: "blur"} | ||
68 | + ], | ||
69 | + password: [ | ||
70 | + {required: true, validator: validatePass, trigger: "blur"} | ||
71 | + ], | ||
72 | + checkPass: [ | ||
73 | + {required: true, validator: validatePass2, trigger: "blur"} | ||
74 | + ] | ||
75 | + } | ||
76 | + } | ||
77 | + }, | ||
78 | + methods: { | ||
79 | + closeCallback () { | ||
80 | + this.$emit("editPwdCallback") | ||
81 | + }, | ||
82 | + submitForm (formName) { | ||
83 | + let that = this | ||
84 | + this.$refs[formName].validate((valid) => { | ||
85 | + if (valid) { | ||
86 | + this.$request.fetchEditPassword({ | ||
87 | + oldPassword: that.ruleForm2.oldPassword, | ||
88 | + newPassword: that.ruleForm2.password | ||
89 | + }).then((res) => { | ||
90 | + that.$message({ | ||
91 | + showClose: true, | ||
92 | + message: res.data.message, | ||
93 | + type: "success" | ||
94 | + }) | ||
95 | + setTimeout(function () { | ||
96 | + Cookies.remove("access_token") | ||
97 | + location.reload() | ||
98 | + }, 3000) | ||
99 | + }).catch((err) => { | ||
100 | + that.$message({ | ||
101 | + showClose: true, | ||
102 | + message: err.data.message, | ||
103 | + type: "error" | ||
104 | + }) | ||
105 | + }) | ||
106 | + } else { | ||
107 | + console.log("error submit!!") | ||
108 | + return false | ||
109 | + } | ||
110 | + }) | ||
111 | + }, | ||
112 | + resetForm (formName) { | ||
113 | + this.$refs[formName].resetFields() | ||
114 | + } | ||
115 | + } | ||
116 | +} | ||
117 | +</script> | ||
118 | + | ||
119 | +<style scoped> | ||
120 | + .demo-ruleForm { | ||
121 | + width: 460px; | ||
122 | + padding-top: 25px; | ||
123 | + } | ||
124 | + | ||
125 | + .card { | ||
126 | + width: 560px; | ||
127 | + padding-bottom: 15px; | ||
128 | + margin: 0px auto; | ||
129 | + } | ||
130 | +</style> |
src/components/userForm/userInfo.vue
0 → 100644
1 | +<template> | ||
2 | + <el-dialog :title="title" width="800px" :visible.sync="visible" destroy-on-close @close="closeCallback"> | ||
3 | + <div class="card"> | ||
4 | + <p class="title"><i class="fa fa-th-large fa-lg"></i>个人资料</p> | ||
5 | + <el-form :model="ruleForm2" status-icon :rules="rules" ref="ruleForm2" label-width="100px" class="demo-ruleForm"> | ||
6 | + <el-form-item label="用户名" prop="username"> | ||
7 | + <el-input v-model="ruleForm2.username" autocomplete="off"></el-input> | ||
8 | + </el-form-item> | ||
9 | + <el-form-item v-if="!userId" label="密码" prop="password"> | ||
10 | + <el-input type="password" v-model="ruleForm2.password" autocomplete="off"></el-input> | ||
11 | + </el-form-item> | ||
12 | + <el-form-item v-if="!userId" label="确认密码" prop="checkPass"> | ||
13 | + <el-input type="password" v-model="ruleForm2.checkPass" autocomplete="off"></el-input> | ||
14 | + </el-form-item> | ||
15 | + <el-form-item label="角色"> | ||
16 | + <el-select v-if="roleName" v-model="ruleForm2.roleId" disabled placeholder="请选择等级"> | ||
17 | + <el-option | ||
18 | + v-for="item in roleData" | ||
19 | + :key="item.id" | ||
20 | + :label="item.name" | ||
21 | + :value="item.id"> | ||
22 | + </el-option> | ||
23 | + </el-select> | ||
24 | + <el-select v-else v-model="ruleForm2.roleId" placeholder="请选择等级"> | ||
25 | + <el-option | ||
26 | + v-for="item in roleData" | ||
27 | + :key="item.id" | ||
28 | + :label="item.name" | ||
29 | + :value="item.id" | ||
30 | + :disabled="item.disabled"> | ||
31 | + </el-option> | ||
32 | + </el-select> | ||
33 | + </el-form-item> | ||
34 | + <el-form-item label="姓名" prop="name"> | ||
35 | + <el-input v-model="ruleForm2.name" autocomplete="off"></el-input> | ||
36 | + </el-form-item> | ||
37 | + <el-form-item label="性别"> | ||
38 | + <el-radio-group v-model="ruleForm2.sex"> | ||
39 | + <el-radio label="1">男</el-radio> | ||
40 | + <el-radio label="2">女</el-radio> | ||
41 | + </el-radio-group> | ||
42 | + </el-form-item> | ||
43 | + <el-form-item label="年龄" prop="age"> | ||
44 | + <el-input v-model="ruleForm2.age" autocomplete="off"></el-input> | ||
45 | + </el-form-item> | ||
46 | + <el-form-item label="手机号" prop="mobilePhone"> | ||
47 | + <el-input v-model="ruleForm2.mobilePhone" autocomplete="off"></el-input> | ||
48 | + </el-form-item> | ||
49 | + <el-form-item label="是否启用"> | ||
50 | + <el-switch v-model="ruleForm2.status"></el-switch> | ||
51 | + </el-form-item> | ||
52 | + <el-form-item label="头像上传"> | ||
53 | + <el-upload | ||
54 | + class="avatar-uploader" | ||
55 | + action="/api/editor/uploadImg" | ||
56 | + :show-file-list="false" | ||
57 | + :on-success="handleAvatarSuccess" | ||
58 | + :before-upload="beforeAvatarUpload"> | ||
59 | + <img v-if="ruleForm2.avatar" :src="ruleForm2.avatar" class="avatar"> | ||
60 | + <i v-else class="el-icon-plus avatar-uploader-icon"></i> | ||
61 | + </el-upload> | ||
62 | + </el-form-item> | ||
63 | + <el-form-item> | ||
64 | + <el-button type="primary" @click="submitForm('ruleForm2')">确 定</el-button> | ||
65 | + <el-button @click="resetForm('ruleForm2')">重 置</el-button> | ||
66 | + </el-form-item> | ||
67 | + </el-form> | ||
68 | + </div> | ||
69 | + </el-dialog> | ||
70 | +</template> | ||
71 | + | ||
72 | +<script> | ||
73 | +export default { | ||
74 | + name: "userInfo", | ||
75 | + props: { | ||
76 | + title: { | ||
77 | + type: String, | ||
78 | + default: "账号信息" | ||
79 | + }, | ||
80 | + dialogVisible: { | ||
81 | + type: Boolean, | ||
82 | + default: false | ||
83 | + }, | ||
84 | + userId: { | ||
85 | + type: String, | ||
86 | + default: "" | ||
87 | + } | ||
88 | + }, | ||
89 | + data () { | ||
90 | + var validatePass = (rule, value, callback) => { | ||
91 | + if (value === "") { | ||
92 | + callback(new Error("请输入密码")) | ||
93 | + } else { | ||
94 | + if (this.ruleForm2.checkPass !== "") { | ||
95 | + this.$refs.ruleForm2.validateField("checkPass") | ||
96 | + } | ||
97 | + callback() | ||
98 | + } | ||
99 | + } | ||
100 | + var validatePass2 = (rule, value, callback) => { | ||
101 | + if (value === "") { | ||
102 | + callback(new Error("请再次输入密码")) | ||
103 | + } else if (value !== this.ruleForm2.password) { | ||
104 | + callback(new Error("两次输入密码不一致!")) | ||
105 | + } else { | ||
106 | + callback() | ||
107 | + } | ||
108 | + } | ||
109 | + return { | ||
110 | + roleName: false, | ||
111 | + roleData: "", | ||
112 | + visible: this.dialogVisible, | ||
113 | + ruleForm2: { | ||
114 | + mobilePhone: "", | ||
115 | + username: "", | ||
116 | + password: "", | ||
117 | + checkPass: "", | ||
118 | + roleId: "", | ||
119 | + status: "", | ||
120 | + sex: "1", | ||
121 | + age: 0, | ||
122 | + name: "", | ||
123 | + avatar: "" | ||
124 | + }, | ||
125 | + rules: { | ||
126 | + username: [ | ||
127 | + { required: true, message: "请输入用户名", trigger: "blur" }, | ||
128 | + { min: 3, max: 18, message: "长度在 3 到 18 个字符", trigger: "blur" } | ||
129 | + ], | ||
130 | + password: [ | ||
131 | + {required: true, validator: validatePass, trigger: "blur"} | ||
132 | + ], | ||
133 | + checkPass: [ | ||
134 | + {required: true, validator: validatePass2, trigger: "blur"} | ||
135 | + ], | ||
136 | + roleId: [ | ||
137 | + { required: true, message: "请选择用户角色", trigger: "change" } | ||
138 | + ] | ||
139 | + } | ||
140 | + } | ||
141 | + }, | ||
142 | + methods: { | ||
143 | + handleAvatarSuccess (res, file) { | ||
144 | + this.ruleForm2.avatar = res.data[0] | ||
145 | + }, | ||
146 | + closeCallback () { | ||
147 | + this.$emit("successCallback") | ||
148 | + }, | ||
149 | + beforeAvatarUpload (file) { | ||
150 | + const isJPG = file.type === "image/jpeg" | ||
151 | + const isPNG = file.type === "image/png" | ||
152 | + const isLt2M = file.size / 1024 / 1024 < 2 | ||
153 | + | ||
154 | + if (!(isJPG || isPNG)) { | ||
155 | + this.$message.error("上传头像图片只能是 JPG/PNG 格式!") | ||
156 | + } | ||
157 | + if (!isLt2M) { | ||
158 | + this.$message.error("上传头像图片大小不能超过 2MB!") | ||
159 | + } | ||
160 | + // eslint-disable-next-line no-mixed-operators | ||
161 | + return isLt2M && isJPG || isPNG | ||
162 | + }, | ||
163 | + getList () { | ||
164 | + let that = this | ||
165 | + this.$request.fetchGetRoleList().then(function (response) { | ||
166 | + that.roleData = response.data.rows | ||
167 | + let userId = that.userId | ||
168 | + if (!userId) { | ||
169 | + return false | ||
170 | + } | ||
171 | + that.$request.fetchGetUserInfoId({id: userId}) | ||
172 | + .then(function (res) { | ||
173 | + console.log(res) | ||
174 | + res.data.password = "" | ||
175 | + if (res.data.status === "1") { | ||
176 | + res.data.status = true | ||
177 | + } else { | ||
178 | + res.data.status = false | ||
179 | + } | ||
180 | + | ||
181 | + that.ruleForm2 = res.data | ||
182 | + that.roleName = true | ||
183 | + for (let i = 0; i < that.roleData.length; i++) { | ||
184 | + if (that.$store.getters.info.role === "超级管理员" && that.$store.getters.info.uid !== userId) { | ||
185 | + that.roleName = false | ||
186 | + } | ||
187 | + } | ||
188 | + return false | ||
189 | + }) | ||
190 | + .catch(function (error) { | ||
191 | + console.log(error) | ||
192 | + }) | ||
193 | + }) | ||
194 | + .catch(function (error) { | ||
195 | + console.log(error) | ||
196 | + }) | ||
197 | + }, | ||
198 | + submitForm (formName) { | ||
199 | + let that = this | ||
200 | + this.$refs[formName].validate((valid) => { | ||
201 | + if (valid) { | ||
202 | + let newData = {} | ||
203 | + let fetchFn = this.$request.fetchEditUser | ||
204 | + if (!that.userId) { | ||
205 | + for (let item in that.ruleForm2) { | ||
206 | + if (item !== "checkPass") { | ||
207 | + newData[item] = that.ruleForm2[item] | ||
208 | + } | ||
209 | + } | ||
210 | + fetchFn = this.$request.fetchRegister | ||
211 | + } else { | ||
212 | + for (let item in that.ruleForm2) { | ||
213 | + if (item !== "password" && item !== "checkPass") { | ||
214 | + newData[item] = that.ruleForm2[item] | ||
215 | + } | ||
216 | + } | ||
217 | + } | ||
218 | + fetchFn(newData).then((res) => { | ||
219 | + that.$message({ | ||
220 | + showClose: true, | ||
221 | + message: res.data.message, | ||
222 | + type: "success" | ||
223 | + }) | ||
224 | + }).catch((err) => { | ||
225 | + console.log(err) | ||
226 | + }) | ||
227 | + } else { | ||
228 | + console.log("error submit!!") | ||
229 | + return false | ||
230 | + } | ||
231 | + }) | ||
232 | + }, | ||
233 | + resetForm (formName) { | ||
234 | + this.$refs[formName].resetFields() | ||
235 | + } | ||
236 | + }, | ||
237 | + mounted () { | ||
238 | + // this.getList() | ||
239 | + } | ||
240 | +} | ||
241 | +</script> | ||
242 | +<style scoped> | ||
243 | + .demo-ruleForm { | ||
244 | + width: 460px; | ||
245 | + padding-top: 25px; | ||
246 | + } | ||
247 | + .el-select { | ||
248 | + width: 100%; | ||
249 | + } | ||
250 | + .card { | ||
251 | + width: 560px; | ||
252 | + padding-bottom: 15px; | ||
253 | + margin: 0px auto; | ||
254 | + } | ||
255 | + .avatar-uploader .el-upload { | ||
256 | + border: 1px dashed #d9d9d9; | ||
257 | + border-radius: 6px; | ||
258 | + cursor: pointer; | ||
259 | + position: relative; | ||
260 | + overflow: hidden; | ||
261 | + } | ||
262 | + .avatar-uploader .el-upload:hover { | ||
263 | + border-color: #409EFF; | ||
264 | + } | ||
265 | + .avatar-uploader-icon { | ||
266 | + font-size: 28px; | ||
267 | + color: #8c939d; | ||
268 | + width: 178px; | ||
269 | + height: 178px; | ||
270 | + line-height: 178px; | ||
271 | + text-align: center; | ||
272 | + } | ||
273 | + .avatar { | ||
274 | + width: 178px; | ||
275 | + height: 178px; | ||
276 | + display: block; | ||
277 | + } | ||
278 | +</style> |
src/config/index.js
0 → 100644
src/directive/permission/button.js
0 → 100644
1 | +export default { | ||
2 | + install (Vue, options) { | ||
3 | + Vue.directive("roleBtn", { | ||
4 | + componentUpdated: function (el, binding) { | ||
5 | + let roleArr = binding.value | ||
6 | + let userRole = JSON.parse(localStorage.getItem("info")).role | ||
7 | + if (roleArr && roleArr.indexOf(userRole) !== -1) { | ||
8 | + return false | ||
9 | + } else { | ||
10 | + el.parentNode.removeChild(el) | ||
11 | + } | ||
12 | + }, | ||
13 | + inserted: function (el, binding) { | ||
14 | + let roleArr = binding.value | ||
15 | + let userRole = JSON.parse(localStorage.getItem("info")).role | ||
16 | + if (roleArr && roleArr.indexOf(userRole) !== -1) { | ||
17 | + return false | ||
18 | + } else { | ||
19 | + el.parentNode.removeChild(el) | ||
20 | + } | ||
21 | + } | ||
22 | + }) | ||
23 | + } | ||
24 | +} | ||
0 | \ No newline at end of file | 25 | \ No newline at end of file |
src/i18n/i18n.js
0 → 100644
1 | +import Vue from "vue" | ||
2 | +import locale from "element-ui/lib/locale" | ||
3 | +import VueI18n from "vue-i18n" | ||
4 | +import messages from "./lang" | ||
5 | + | ||
6 | +Vue.use(VueI18n) | ||
7 | +const i18n = new VueI18n({ | ||
8 | + locale: localStorage.lang || "cn", | ||
9 | + messages | ||
10 | +}) | ||
11 | +locale.i18n((key, value) => i18n.t(key, value)) | ||
12 | + | ||
13 | +export default i18n |
src/i18n/lang/cn.js
0 → 100644
1 | + | ||
2 | +import zhLocale from "element-ui/lib/locale/lang/zh-CN" | ||
3 | +const cn = { | ||
4 | + routeName: { | ||
5 | + home: "主页", | ||
6 | + icon: "图标", | ||
7 | + builtInIcon: "内置图标", | ||
8 | + permissions: "权限管理", | ||
9 | + multiDirectory: "多级目录", | ||
10 | + "menu2-1": "二级-1", | ||
11 | + "menu2-3": "二级-3", | ||
12 | + "menu3-1": "三级-1", | ||
13 | + "menu4-1": "四级-1", | ||
14 | + }, | ||
15 | + rightMenu: { | ||
16 | + close: "关闭", | ||
17 | + closeOther: "关闭其他", | ||
18 | + closeAll: "全部关闭" | ||
19 | + }, | ||
20 | + role: { | ||
21 | + superAdmin: "超级管理员", | ||
22 | + admin: "管理员", | ||
23 | + ordinary: "普通用户" | ||
24 | + }, | ||
25 | + userDropdownMenu: { | ||
26 | + basicInfor: "基本资料", | ||
27 | + changePassword: "修改密码", | ||
28 | + logout: "退出" | ||
29 | + }, | ||
30 | + | ||
31 | + ...zhLocale // 合并element-ui内置翻译 | ||
32 | +} | ||
33 | + | ||
34 | +export default cn |
src/i18n/lang/en.js
0 → 100644
1 | +import enLocale from "element-ui/lib/locale/lang/en" | ||
2 | +const en = { | ||
3 | + routeName: { | ||
4 | + home: "home", | ||
5 | + icon: "icon", | ||
6 | + builtInIcon: "builtInIcon", | ||
7 | + permissions: "permissions", | ||
8 | + multiDirectory: "multiDirectory", | ||
9 | + "menu2-1": "menu2-1", | ||
10 | + "menu2-3": "menu2-3", | ||
11 | + "menu3-1": "menu3-1", | ||
12 | + "menu4-1": "menu4-1", | ||
13 | + }, | ||
14 | + rightMenu: { | ||
15 | + close: "close", | ||
16 | + closeOther: "closeOther", | ||
17 | + closeAll: "closeAll" | ||
18 | + }, | ||
19 | + role: { | ||
20 | + superAdmin: "superAdmin", | ||
21 | + admin: "admin", | ||
22 | + ordinary: "ordinary" | ||
23 | + }, | ||
24 | + userDropdownMenu: { | ||
25 | + basicInfor: "basicInfor", | ||
26 | + changePassword: "changePassword", | ||
27 | + logout: "logout" | ||
28 | + }, | ||
29 | + | ||
30 | + ...enLocale // 合并element-ui内置翻译 | ||
31 | +} | ||
32 | + | ||
33 | +export default en |
src/i18n/lang/index.js
0 → 100644
src/router/index.js
0 → 100755
1 | +import en from "../i18n/lang/en" | ||
2 | +import Vue from "vue" | ||
3 | +import Router from "vue-router" | ||
4 | +import Login from "@/views/login/index" | ||
5 | +import Layout from "@/views/layout/layout" | ||
6 | +import HomeMain from "@/views/index/mainIndex" | ||
7 | + | ||
8 | +// 不是必须加载的组件使用懒加载 | ||
9 | +const NotFound = () => import("@/views/page404") | ||
10 | + | ||
11 | +/** | ||
12 | + * 重写路由的push方法 | ||
13 | + */ | ||
14 | +const routerPush = Router.prototype.push | ||
15 | +Router.prototype.push = function push (location) { | ||
16 | + return routerPush.call(this, location).catch(error => error) | ||
17 | +} | ||
18 | +Vue.use(Router) | ||
19 | +let routeName = en.routeName | ||
20 | +let defaultRouter = [ | ||
21 | + { path: "/", | ||
22 | + redirect: "/index", | ||
23 | + hidden: true, | ||
24 | + children: [] | ||
25 | + }, | ||
26 | + { | ||
27 | + path: "/login", | ||
28 | + component: Login, | ||
29 | + name: "登录", | ||
30 | + hidden: true, | ||
31 | + children: [] | ||
32 | + }, | ||
33 | + { | ||
34 | + path: "/index", | ||
35 | + iconCls: "fa fa-dashboard", // 图标样式class | ||
36 | + name: "首页", | ||
37 | + component: Layout, | ||
38 | + alone: true, | ||
39 | + children: [ | ||
40 | + { | ||
41 | + path: "/index", | ||
42 | + iconCls: "fa fa-dashboard", // 图标样式class | ||
43 | + name: "主页", | ||
44 | + component: HomeMain, | ||
45 | + children: [] | ||
46 | + } | ||
47 | + ] | ||
48 | + }, | ||
49 | + { | ||
50 | + path: "/404", | ||
51 | + component: NotFound, | ||
52 | + name: "404", | ||
53 | + hidden: true, | ||
54 | + children: [] | ||
55 | + } | ||
56 | +] | ||
57 | + | ||
58 | +export default new Router({ | ||
59 | + routes: defaultRouter | ||
60 | +}) | ||
61 | +export {defaultRouter} |
src/router/permission.js
0 → 100644
1 | +import NProgress from "nprogress" | ||
2 | +import en from "../i18n/lang/en" | ||
3 | +import Layout from "@/views/layout/layout" | ||
4 | +import CommerViews from "@/views/commerViews" | ||
5 | +import router from "./index" | ||
6 | +import store from "../store" | ||
7 | +let routeName = en.routeName | ||
8 | + | ||
9 | +const Erji = () => import("@/views/duoji/erji") | ||
10 | +const Sanji = () => import("@/views/duoji/sanji") | ||
11 | + let addrouters = [ //测试用,后续后端获取 | ||
12 | + | ||
13 | + { | ||
14 | + path: "/", | ||
15 | + iconCls: "fa fa-server", | ||
16 | + // name: routeName.multiDirectory, | ||
17 | + name: '多级', | ||
18 | + component: Layout, | ||
19 | + children: [ | ||
20 | + { | ||
21 | + path: "/erji1", | ||
22 | + iconCls: "fa fa-server", | ||
23 | + // name: routeName["menu2-1"], | ||
24 | + name: '二级', | ||
25 | + component: Erji, | ||
26 | + meta:{ | ||
27 | + role:['admin'] | ||
28 | + }, | ||
29 | + children: [] | ||
30 | + }, | ||
31 | + { | ||
32 | + path: "/erji3", | ||
33 | + iconCls: "fa fa-server", | ||
34 | + name: "三级", | ||
35 | + component: CommerViews, // 无限极菜单的容器 | ||
36 | + children: [ | ||
37 | + { | ||
38 | + path: "/sanji1", | ||
39 | + iconCls: "fa fa-server", | ||
40 | + name: "三级子页面", | ||
41 | + component: Sanji, | ||
42 | + children: [] | ||
43 | + }, | ||
44 | + ] | ||
45 | + } | ||
46 | + ] | ||
47 | + }, | ||
48 | + | ||
49 | + { path: "*", | ||
50 | + redirect: "/404", | ||
51 | + hidden: true, | ||
52 | + children: [] | ||
53 | + } | ||
54 | +] | ||
55 | + | ||
56 | + | ||
57 | +// 获取角色信息,根据用户权限动态加载路由 | ||
58 | +router.beforeEach((to, from, next) => { | ||
59 | + NProgress.start() | ||
60 | + if (store.getters.token) { | ||
61 | + if (to.path === "/login") { | ||
62 | + next({path: "/"}) | ||
63 | + } else { | ||
64 | + if (!store.getters.info.role) { | ||
65 | + !(async function getAddRouters () { | ||
66 | + // 省略 axios 请求代码 通过 token 向后台请求用户权限等信息,这里用假数据赋值 | ||
67 | + await store.dispatch("setInfo", { | ||
68 | + role: "superAdmin", | ||
69 | + permissions: "超级管理员", | ||
70 | + name:"张老师", | ||
71 | + }) | ||
72 | + await store.dispatch("newRoutes",addrouters) | ||
73 | + let newAddRouters = store.getters.addRouters | ||
74 | + await router.addRoutes(newAddRouters) | ||
75 | + next({path: to.path}) | ||
76 | + }()) | ||
77 | + } else { | ||
78 | + let is404 = to.matched.some(record => { | ||
79 | + if (record.meta.role) { | ||
80 | + return store.getters.info.authorityRouter === -1 | ||
81 | + } | ||
82 | + }) | ||
83 | + if (is404) { | ||
84 | + next({path: "/404"}) | ||
85 | + return false | ||
86 | + } | ||
87 | + next() | ||
88 | + } | ||
89 | + } | ||
90 | + } else { | ||
91 | + if (to.path === "/login") { | ||
92 | + next() | ||
93 | + } | ||
94 | + next({path: "/login"}) | ||
95 | + } | ||
96 | +}) | ||
97 | + | ||
98 | +router.afterEach(() => { | ||
99 | + NProgress.done() | ||
100 | +}) | ||
101 | + | ||
102 | + | ||
103 | +// // 真实使用 | ||
104 | +// import fetchUser from "@/api/apis/user" | ||
105 | +// | ||
106 | +// router.beforeEach((to, from, next) => { | ||
107 | +// if (store.getters.token && store.getters.token !== "undefined") { | ||
108 | +// // store.dispatch('setToken', store.getters.token) | ||
109 | +// if (to.path === "/login") { | ||
110 | +// next({path: "/"}) | ||
111 | +// } else { | ||
112 | +// if (!store.getters.info) { | ||
113 | +// (async function getAddRouters () { | ||
114 | +// fetchUser.fetchGetUserInfo().then(async function (response) { | ||
115 | +// await store.dispatch("setInfo", response.data) | ||
116 | + // await store.dispatch("newRoutes", store.getters.info.authorityRouter) | ||
117 | +// await router.addRoutes(store.getters.addRouters) | ||
118 | +// next({path: "/index"}) | ||
119 | +// }).catch(function (error) { | ||
120 | +// console.log(error) | ||
121 | +// }) | ||
122 | +// }()) | ||
123 | +// } else { | ||
124 | +// let is404 = to.matched.some(record => { | ||
125 | +// console.log(record) | ||
126 | +// if (record.meta.role) { | ||
127 | +// return store.getters.info.authorityRouter === -1 | ||
128 | +// } | ||
129 | +// }) | ||
130 | +// if (is404) { | ||
131 | +// next({path: "/404"}) | ||
132 | +// return false | ||
133 | +// } | ||
134 | +// next() | ||
135 | +// } | ||
136 | +// } | ||
137 | +// } else { | ||
138 | +// if (to.path === "/login") { | ||
139 | +// next() | ||
140 | +// } | ||
141 | +// next({path: "/login"}) | ||
142 | +// } | ||
143 | +// }) |
src/store/index.js
0 → 100644
1 | +import Vue from "vue" | ||
2 | +import Vuex from "vuex" | ||
3 | +import Cookies from "js-cookie" | ||
4 | +import routerData from "./modules/routerData" | ||
5 | +import role from "./modules/role" | ||
6 | +import layout from "./modules/layout/index" | ||
7 | + | ||
8 | +Vue.use(Vuex) | ||
9 | + | ||
10 | +const store = new Vuex.Store({ | ||
11 | + state: { | ||
12 | + token: Cookies.get("token") | ||
13 | + }, | ||
14 | + mutations: { | ||
15 | + setToken (state, token) { | ||
16 | + state.token = token | ||
17 | + Cookies.set("token", token, { expires: 1 / 24 }) | ||
18 | + } | ||
19 | + }, | ||
20 | + actions: { | ||
21 | + setToken ({commit}, token) { | ||
22 | + return new Promise((resolve, reject) => { | ||
23 | + commit("setToken", token) | ||
24 | + resolve() | ||
25 | + }) | ||
26 | + } | ||
27 | + }, | ||
28 | + getters: { | ||
29 | + addRouters: state => state.routerData.addRouters, | ||
30 | + token: state => state.token, | ||
31 | + info: state => state.role.info, | ||
32 | + routers: state => state.routerData.routers, | ||
33 | + logoShow: state => state.layout.logoShow, | ||
34 | + isCollapse: state => state.layout.isCollapse, | ||
35 | + uniquerouter: state => state.layout.uniquerouter, | ||
36 | + tabnavBox: state => state.layout.tabnavBox, | ||
37 | + rightNav: state => state.layout.rightNav | ||
38 | + }, | ||
39 | + modules: { | ||
40 | + routerData, | ||
41 | + role, | ||
42 | + layout | ||
43 | + } | ||
44 | +}) | ||
45 | + | ||
46 | +export default store |
src/store/modules/layout/index.js
0 → 100644
1 | + | ||
2 | +export default { | ||
3 | + state: { | ||
4 | + isCollapse: false, | ||
5 | + logoShow: false, | ||
6 | + uniquerouter: true, | ||
7 | + rightNav: {}, | ||
8 | + tabnavBox: JSON.parse(sessionStorage.getItem("addTab")) || [{ | ||
9 | + title: "home", | ||
10 | + path: "/index" | ||
11 | + }] | ||
12 | + }, | ||
13 | + mutations: { | ||
14 | + addTab (state, arg) { | ||
15 | + state.isActive = arg.path | ||
16 | + if (state.tabnavBox[0] && state.tabnavBox[0].title !== "home") { | ||
17 | + state.tabnavBox.unshift({ | ||
18 | + title: "home", | ||
19 | + path: "/index" | ||
20 | + }) | ||
21 | + } | ||
22 | + | ||
23 | + for (let i = 0; i < state.tabnavBox.length; i++) { | ||
24 | + if (state.tabnavBox[i].path === arg.path) { | ||
25 | + return false | ||
26 | + } | ||
27 | + } | ||
28 | + state.tabnavBox.push({ | ||
29 | + title: arg.title, | ||
30 | + path: arg.path | ||
31 | + }) | ||
32 | + | ||
33 | + sessionStorage.setItem("addTab", JSON.stringify(state.tabnavBox)) | ||
34 | + }, | ||
35 | + openMenu (state, arg) { | ||
36 | + state.rightNav = arg | ||
37 | + }, | ||
38 | + removeTab (state, arg) { | ||
39 | + let index = state.tabnavBox.findIndex(function (value, key) { | ||
40 | + return value.path === arg.tabItem.path | ||
41 | + }) | ||
42 | + state.tabnavBox.splice(index, 1) | ||
43 | + if (arg.tabItem.path === arg.fullPath) { | ||
44 | + let tabActive = state.tabnavBox[index] || state.tabnavBox[index - 1] | ||
45 | + arg.router.push(tabActive.path) | ||
46 | + } | ||
47 | + sessionStorage.setItem("addTab", JSON.stringify(state.tabnavBox)) | ||
48 | + }, | ||
49 | + removeOtherTab (state, arg) { | ||
50 | + state.tabnavBox = [{ | ||
51 | + title: "home", | ||
52 | + path: "/index" | ||
53 | + }] | ||
54 | + if (arg.all) { | ||
55 | + arg.router.push("/index") | ||
56 | + return false | ||
57 | + } | ||
58 | + state.tabnavBox.push(arg.tabItem) | ||
59 | + arg.router.push(arg.tabItem.path) | ||
60 | + sessionStorage.setItem("addTab", JSON.stringify(state.tabnavBox)) | ||
61 | + }, | ||
62 | + collapse (state, arg) { | ||
63 | + state.isCollapse = !state.isCollapse | ||
64 | + if (state.logoShow) { | ||
65 | + setTimeout(function () { | ||
66 | + state.logoShow = false | ||
67 | + }, 300) | ||
68 | + } else { | ||
69 | + state.logoShow = true | ||
70 | + } | ||
71 | + } | ||
72 | + }, | ||
73 | + actions: { | ||
74 | + addTab ({commit}, arg) { | ||
75 | + commit("addTab", arg) | ||
76 | + }, | ||
77 | + openMenu ({commit}, arg) { | ||
78 | + commit("openMenu", arg) | ||
79 | + }, | ||
80 | + removeTab ({commit}, arg) { | ||
81 | + commit("removeTab", arg) | ||
82 | + }, | ||
83 | + removeOtherTab ({commit}, arg) { | ||
84 | + commit("removeOtherTab", arg) | ||
85 | + }, | ||
86 | + collapse ({commit}, arg) { | ||
87 | + commit("collapse", arg) | ||
88 | + } | ||
89 | + } | ||
90 | +} |
src/store/modules/role.js
0 → 100644
1 | +import store from "../index" | ||
2 | +import router from "../../router/index" | ||
3 | +export default { | ||
4 | + state: { | ||
5 | + info: "" // 每次刷新都要通过token请求个人信息来筛选动态路由 | ||
6 | + }, | ||
7 | + mutations: { | ||
8 | + setInfo (state, data) { | ||
9 | + if (data.authorityRouter) { | ||
10 | + data.authorityRouter = data.authorityRouter.indexOf(",") !== -1 ? data.authorityRouter.split(",") : new Array(data.authorityRouter) | ||
11 | + } else { | ||
12 | + data.authorityRouter = [] | ||
13 | + } | ||
14 | + | ||
15 | + | ||
16 | + | ||
17 | + state.info = { | ||
18 | + role: data.role, | ||
19 | + name: data.name, | ||
20 | + authorityRouter: data.authorityRouter, | ||
21 | + avatar: data.avatar ? data.avatar : "", | ||
22 | + uid: data.id | ||
23 | + } | ||
24 | + localStorage.setItem("info", JSON.stringify(store.getters.info)) | ||
25 | + } | ||
26 | + }, | ||
27 | + actions: { | ||
28 | + setInfo ({commit}, data) { | ||
29 | + commit("setInfo", data) | ||
30 | + } | ||
31 | + } | ||
32 | +} |
src/store/modules/routerData.js
0 → 100644
1 | +import {defaultRouter} from "@/router/index" | ||
2 | + | ||
3 | +const routerData = { | ||
4 | + state: { | ||
5 | + routers: [], | ||
6 | + addRouters: [], | ||
7 | + }, | ||
8 | + mutations: { | ||
9 | + setRouters: (state, routers) => { | ||
10 | + state.addRouters = routers // 保存动态路由用来addRouter | ||
11 | + state.routers = defaultRouter.concat(routers) // 所有有权限的路由表,用来生成菜单列表 | ||
12 | + }, | ||
13 | + }, | ||
14 | + actions: { | ||
15 | + newRoutes ({commit},addRouter) { | ||
16 | + // 通过递归路由表,删除掉没有权限的路由 | ||
17 | + function eachSelect (routers) { | ||
18 | + for (let i = 0; i < routers.length; i++) { | ||
19 | + if (routers[i].meta && routers[i].meta.role.length && routers[i].meta.role.indexOf(userRole) === -1) { | ||
20 | + routers.splice(i, 1) | ||
21 | + i = i !== 0 ? i - 1 : i | ||
22 | + } | ||
23 | + if (routers[i].children && routers[i].children.length) { | ||
24 | + eachSelect(routers[i].children, userRole) | ||
25 | + } | ||
26 | + } | ||
27 | + } | ||
28 | + // 仅限演示 | ||
29 | + let newArr = [...addRouter] // 拷贝这个数组是因为做权限测试的时候可以从低级切回到高级角色,仅限演示,正式开发时省略这步直接使用 addRouter | ||
30 | + // eachSelect(newArr) | ||
31 | + commit("setRouters", newArr) | ||
32 | + | ||
33 | + // 正式开发 | ||
34 | + // eachSelect(addRouter, role) | ||
35 | + // commit('setRouters', addRouter) | ||
36 | + } | ||
37 | + } | ||
38 | +} | ||
39 | + | ||
40 | +export default routerData |
src/utils/global.js
0 → 100644
1 | +import rules from "./rules" | ||
2 | +import request from "@/api" | ||
3 | +import * as echarts from "echarts" | ||
4 | + | ||
5 | +export default { | ||
6 | + install (Vue, options) { | ||
7 | + Vue.prototype.$echarts = echarts | ||
8 | + Vue.prototype.$request = request | ||
9 | + Vue.prototype.$rules = rules | ||
10 | + /** 时间字符串 | ||
11 | + * @method $getDateDiff | ||
12 | + * @param timespan | ||
13 | + */ | ||
14 | + Vue.prototype.$getDateDiff = function (timespan) { | ||
15 | + var dateTime = new Date(timespan) | ||
16 | + var year = dateTime.getFullYear() | ||
17 | + var month = (dateTime.getMonth() + 1) < 10 ? "0" + (dateTime.getMonth() + 1) : (dateTime.getMonth() + 1) | ||
18 | + var day = dateTime.getDate() < 10 ? "0" + dateTime.getDate() : dateTime.getDate() | ||
19 | + var hour = dateTime.getHours() < 10 ? "0" + dateTime.getHours() : dateTime.getHours() | ||
20 | + var minute = dateTime.getMinutes() < 10 ? "0" + dateTime.getMinutes() : dateTime.getMinutes() | ||
21 | + var seconds = dateTime.getSeconds() < 10 ? "0" + dateTime.getSeconds() : dateTime.getSeconds() | ||
22 | + var now = new Date() | ||
23 | + var nowNew = now.getTime() | ||
24 | + var milliseconds = 0 | ||
25 | + var timeSpanStr | ||
26 | + milliseconds = nowNew - dateTime | ||
27 | + | ||
28 | + if (milliseconds <= 1000 * 60 * 1) { | ||
29 | + timeSpanStr = "刚刚" | ||
30 | + } else if (1000 * 60 * 1 < milliseconds && milliseconds <= 1000 * 60 * 60) { | ||
31 | + timeSpanStr = Math.round((milliseconds / (1000 * 60))) + "分钟前" | ||
32 | + } else if (1000 * 60 * 60 * 1 < milliseconds && milliseconds <= 1000 * 60 * 60 * 24) { | ||
33 | + timeSpanStr = Math.round(milliseconds / (1000 * 60 * 60)) + "小时前" | ||
34 | + } else if (1000 * 60 * 60 * 24 < milliseconds && milliseconds <= 1000 * 60 * 60 * 24 * 3) { | ||
35 | + timeSpanStr = Math.round(milliseconds / (1000 * 60 * 60 * 24)) + "天前" | ||
36 | + } else if (milliseconds > 1000 * 60 * 60 * 24 * 3 && year === now.getFullYear()) { | ||
37 | + timeSpanStr = month + "-" + day + " " + hour + ":" + minute + ":" + seconds | ||
38 | + } else { | ||
39 | + timeSpanStr = year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + seconds | ||
40 | + } | ||
41 | + return timeSpanStr | ||
42 | + } | ||
43 | + | ||
44 | + /** 当前地址ip | ||
45 | + * @method $path | ||
46 | + * @param {} | ||
47 | + */ | ||
48 | + Vue.prototype.$path = process.env.API_HOST | ||
49 | + | ||
50 | + /** 传入路径转换成完整连接 | ||
51 | + * @method $getPath | ||
52 | + * @param {url: 路径} | ||
53 | + */ | ||
54 | + Vue.prototype.$getPath = function (url) { | ||
55 | + const base = process.env.API_HOST | ||
56 | + if (/^http/.test(url)) return url | ||
57 | + return base + url | ||
58 | + } | ||
59 | + /** 是否开发模式 | ||
60 | + * @method $env | ||
61 | + * @param {} | ||
62 | + */ | ||
63 | + Vue.prototype.$env = process.env.NODE_ENV | ||
64 | + | ||
65 | + /** 导出,下载处理文件流 | ||
66 | + * @method $exportClick | ||
67 | + * @param {res:文件流,name : 下载文件名} | ||
68 | + */ | ||
69 | + Vue.prototype.$exportClick = function (res, name = "下载.zip") { | ||
70 | + const content = res | ||
71 | + const blob = new Blob([content]) | ||
72 | + const fileName = name | ||
73 | + if ("download" in document.createElement("a")) { // 非IE下载 | ||
74 | + const elink = document.createElement("a") | ||
75 | + elink.download = fileName | ||
76 | + elink.style.display = "none" | ||
77 | + elink.href = URL.createObjectURL(blob) | ||
78 | + document.body.appendChild(elink) | ||
79 | + elink.click() | ||
80 | + URL.revokeObjectURL(elink.href) // 释放URL 对象 | ||
81 | + document.body.removeChild(elink) | ||
82 | + } else { // IE10+下载 | ||
83 | + navigator.msSaveBlob(blob, fileName) | ||
84 | + } | ||
85 | + } | ||
86 | + | ||
87 | + /** 当res.code === 200 时 | ||
88 | + * @method $restBack | ||
89 | + * @param res | ||
90 | + * @param fn | ||
91 | + * @param message | ||
92 | + * @param type | ||
93 | + */ | ||
94 | + Vue.prototype.$restBack = function (res, fn = () => {}, message, type = "success") { | ||
95 | + if (res.code === 200) { | ||
96 | + this.$message({ | ||
97 | + message: message || res.message, | ||
98 | + type: type | ||
99 | + }) | ||
100 | + fn() | ||
101 | + } | ||
102 | + } | ||
103 | + } | ||
104 | +} |
src/utils/index.js
0 → 100644
1 | + | ||
2 | +import CryptoJS from "crypto-js" | ||
3 | + | ||
4 | +const encryptKey = "WfJTKO9S4eLkrPz2JKrAnzdb" | ||
5 | +const encryptIV = "D076D35C" | ||
6 | + | ||
7 | +// 深度复制 | ||
8 | +export function deepClone (obj) { | ||
9 | + let result = Array.isArray(obj) ? [] : {} | ||
10 | + for (let key in obj) { | ||
11 | + if (obj.hasOwnProperty(key)) { | ||
12 | + if (typeof obj[key] === "object") { | ||
13 | + result[key] = deepClone(obj[key]) | ||
14 | + } else { | ||
15 | + result[key] = obj[key] | ||
16 | + } | ||
17 | + } | ||
18 | + } | ||
19 | + return result | ||
20 | +} | ||
21 | + | ||
22 | +// 3DES加密 | ||
23 | +export function desEncrypt (str, key = encryptKey, iv = encryptIV) { | ||
24 | + var cryptoKey = CryptoJS.enc.Utf8.parse(key) | ||
25 | + var cryptoIv = CryptoJS.enc.Utf8.parse(iv.substr(0, 8)) | ||
26 | + var encodeStr = CryptoJS.TripleDES.encrypt(str, cryptoKey, { | ||
27 | + iv: cryptoIv, | ||
28 | + mode: CryptoJS.mode.CBC, | ||
29 | + padding: CryptoJS.pad.Pkcs7 | ||
30 | + }) | ||
31 | + return encodeStr.toString() | ||
32 | +} | ||
33 | + | ||
34 | +// 3DES解密 | ||
35 | +export function desDecrypt (str, key = encryptKey, iv = encryptIV) { | ||
36 | + var cryptoKey = CryptoJS.enc.Utf8.parse(key) | ||
37 | + var cryptoIv = CryptoJS.enc.Utf8.parse(iv.substr(0, 8)) | ||
38 | + var decryptStr = CryptoJS.TripleDES.decrypt(str, cryptoKey, { | ||
39 | + iv: cryptoIv, | ||
40 | + mode: CryptoJS.mode.CBC, | ||
41 | + padding: CryptoJS.pad.Pkcs7 | ||
42 | + }) | ||
43 | + return decryptStr.toString(CryptoJS.enc.Utf8) | ||
44 | +} | ||
45 | + | ||
46 | +// 随机生成由字母+数字的字符串 | ||
47 | +export function randomWord (randomFlag, min, max) { | ||
48 | + // randomFlag: Boolean 是否随机个数 | ||
49 | + // min 最少个数 | ||
50 | + // max 最大个数 | ||
51 | + var str = "" | ||
52 | + var range = min | ||
53 | + var arr = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"] | ||
54 | + // 随机产生 | ||
55 | + if (randomFlag) { | ||
56 | + range = Math.round(Math.random() * (max - min)) + min | ||
57 | + } | ||
58 | + var pos = "" | ||
59 | + for (var i = 0; i < range; i++) { | ||
60 | + pos = Math.round(Math.random() * (arr.length - 1)) | ||
61 | + str += arr[pos] | ||
62 | + } | ||
63 | + return str | ||
64 | +} | ||
65 | + | ||
66 | +// 判断数组中是否存在相同值 | ||
67 | +export function hasRepeatValue (arr, key = null) { | ||
68 | + if (key) arr = arr.map(d => d[key]) | ||
69 | + if (arr.length) { | ||
70 | + let nameNum = arr.reduce((pre, cur) => { | ||
71 | + if (cur in pre) { | ||
72 | + pre[cur]++ | ||
73 | + } else { | ||
74 | + pre[cur] = 1 | ||
75 | + } | ||
76 | + return pre | ||
77 | + }, {}) | ||
78 | + return Object.values(nameNum).findIndex(d => d > 1) < 0 | ||
79 | + } | ||
80 | + return true | ||
81 | +} | ||
82 | + | ||
83 | +// 获取cookie值 | ||
84 | +export function getCookie (name, defaultValue) { | ||
85 | + const result = new RegExp("(^| )" + name + "=([^;]*)(;|$)") | ||
86 | + return result[0] === document.cookie.match(result[1]) ? unescape(result[0][2]) : defaultValue | ||
87 | +} | ||
88 | + | ||
89 | +// base64ToFile | ||
90 | +export function base64ToFile (base64Data, tempfilename, contentType) { | ||
91 | + contentType = contentType || "" | ||
92 | + var sliceSize = 1024 | ||
93 | + var byteCharacters = atob(base64Data) | ||
94 | + var bytesLength = byteCharacters.length | ||
95 | + var slicesCount = Math.ceil(bytesLength / sliceSize) | ||
96 | + var byteArrays = new Array(slicesCount) | ||
97 | + | ||
98 | + for (var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) { | ||
99 | + var begin = sliceIndex * sliceSize | ||
100 | + var end = Math.min(begin + sliceSize, bytesLength) | ||
101 | + | ||
102 | + var bytes = new Array(end - begin) | ||
103 | + for (var offset = begin, i = 0; offset < end; ++i, ++offset) { | ||
104 | + bytes[i] = byteCharacters[offset].charCodeAt(0) | ||
105 | + } | ||
106 | + byteArrays[sliceIndex] = new Uint8Array(bytes) | ||
107 | + } | ||
108 | + var file = new File(byteArrays, tempfilename, { type: contentType }) | ||
109 | + return file | ||
110 | +} | ||
111 | + | ||
112 | +// 将base64转换为文件 | ||
113 | +export function dataURLtoFile (dataurl, filename) { | ||
114 | + var arr = dataurl.split(",") | ||
115 | + var mime = arr[0].match(/:(.*?);/)[1] | ||
116 | + var bstr = atob(arr[1]) | ||
117 | + var n = bstr.length | ||
118 | + var u8arr = new Uint8Array(n) | ||
119 | + while (n--) { | ||
120 | + u8arr[n] = bstr.charCodeAt(n) | ||
121 | + } | ||
122 | + return new File([u8arr], filename, { type: mime }) | ||
123 | +} | ||
124 | + | ||
125 | +// 将图片转换为Base64 | ||
126 | +export function getImgToBase64 (url, callback, outputFormat) { | ||
127 | + var canvas = document.createElement("canvas") | ||
128 | + var ctx = canvas.getContext("2d") | ||
129 | + var img = new Image() | ||
130 | + img.crossOrigin = "Anonymous" | ||
131 | + img.onload = function () { | ||
132 | + canvas.height = img.height | ||
133 | + canvas.width = img.width | ||
134 | + ctx.drawImage(img, 0, 0) | ||
135 | + var dataURL = canvas.toDataURL(outputFormat || "image/png") | ||
136 | + callback(dataURL) | ||
137 | + canvas = null | ||
138 | + } | ||
139 | + img.src = url | ||
140 | +} | ||
141 | + | ||
142 | +// 转换级联下拉数据 | ||
143 | +export function loopOptions (list, option = {}) { | ||
144 | + option = { | ||
145 | + value: "id", | ||
146 | + label: "name", | ||
147 | + children: "children", | ||
148 | + ...option | ||
149 | + } | ||
150 | + if (list instanceof Array && list.length) { | ||
151 | + return list.map((d, i) => { | ||
152 | + d.value = d[option.value] || i + 1 | ||
153 | + d.label = d[option.label] | ||
154 | + if (d[option.children]) { | ||
155 | + d[option.children] = loopOptions(d[option.children], option) | ||
156 | + } | ||
157 | + return d | ||
158 | + }) | ||
159 | + } | ||
160 | + return [] | ||
161 | +} | ||
162 | + | ||
163 | +// 通过Id获取级联数据id数组 | ||
164 | +export function getTreeIds (tree, currentId, key = "id") { | ||
165 | + let parent = {} | ||
166 | + let pid = {} | ||
167 | + const loop = (list, level) => { | ||
168 | + if (list instanceof Array && list.length) { | ||
169 | + for (let index = 0; index < list.length; index++) { | ||
170 | + const d = list[index] | ||
171 | + parent[level] = d.id | ||
172 | + if (d[key] === currentId) { | ||
173 | + for (let idx = 1; idx <= level; idx++) { | ||
174 | + pid[idx] = parent[idx] | ||
175 | + } | ||
176 | + break | ||
177 | + } else if (d.children) { | ||
178 | + loop(d.children, level + 1) | ||
179 | + } | ||
180 | + } | ||
181 | + } | ||
182 | + } | ||
183 | + loop(tree, 1) | ||
184 | + let result = [] | ||
185 | + Object.keys(pid).sort((a, b) => a - b).forEach(k => { | ||
186 | + result.push(pid[k]) | ||
187 | + }) | ||
188 | + return result | ||
189 | +} | ||
190 | + | ||
191 | +// 秒转换时分秒 | ||
192 | +export function transverterMss (result) { | ||
193 | + var h = Math.floor(result / 3600) < 10 ? "0" + Math.floor(result / 3600) : Math.floor(result / 3600) | ||
194 | + var m = Math.floor((result / 60 % 60)) < 10 ? "0" + Math.floor((result / 60 % 60)) : Math.floor((result / 60 % 60)) | ||
195 | + var s = Math.floor((result % 60)) < 10 ? "0" + Math.floor((result % 60)) : Math.floor((result % 60)) | ||
196 | + return h + ":" + m + ":" + s | ||
197 | +} | ||
198 | + | ||
199 | +// 获取日期时间戳 | ||
200 | +export function getTime (dayNum) { | ||
201 | + var myDate = new Date() | ||
202 | + var lw = new Date(myDate - 1000 * 60 * 60 * 24 * dayNum)// 最后一个数字多少天前的意思 | ||
203 | + var lastY = lw.getFullYear() | ||
204 | + var lastM = lw.getMonth() + 1 | ||
205 | + var lastD = lw.getDate() | ||
206 | + var startdate = lastY + "-" + (lastM < 10 ? "0" + lastM : lastM) + "-" + (lastD < 10 ? "0" + lastD : lastD) | ||
207 | + var b = startdate.split(/\D/) | ||
208 | + var date = new Date(b[0], b[1] - 1, b[2]) | ||
209 | + var time = date.getTime() | ||
210 | + return time | ||
211 | +} | ||
212 | + | ||
213 | +// 获取几天之前日期 | ||
214 | +export function getData (dayNum) { | ||
215 | + var myDate = new Date() | ||
216 | + var lw = new Date(myDate - 1000 * 60 * 60 * 24 * dayNum)// 最后一个数字多少天前的意思 | ||
217 | + var lastY = lw.getFullYear() | ||
218 | + var lastM = lw.getMonth() + 1 | ||
219 | + var lastD = lw.getDate() | ||
220 | + var startdate = lastY + "-" + (lastM < 10 ? "0" + lastM : lastM) + "-" + (lastD < 10 ? "0" + lastD : lastD) | ||
221 | + return startdate | ||
222 | +} | ||
223 | + | ||
224 | +// 日期转换时间戳 | ||
225 | +export function getNewTime (dayNum) { | ||
226 | + var b = dayNum.split(/\D/) | ||
227 | + var date = new Date(b[0], b[1] - 1, b[2]) | ||
228 | + var time = date.getTime() | ||
229 | + return time | ||
230 | +} |
src/utils/rules.js
0 → 100644
1 | +export default { | ||
2 | + // 必选 | ||
3 | + requiredSelect: (mes = "此项必选", trigger = ["blur", "change"]) => { | ||
4 | + return { | ||
5 | + required: true, | ||
6 | + message: mes, | ||
7 | + trigger: trigger | ||
8 | + } | ||
9 | + }, | ||
10 | + // 固定长度 | ||
11 | + $length: (len = 1, message = `长度必须为${len}`, trigger = ["blur", "change"]) => { | ||
12 | + return { | ||
13 | + len: len, | ||
14 | + message: message, | ||
15 | + trigger: trigger | ||
16 | + } | ||
17 | + }, | ||
18 | + // 长度验证 | ||
19 | + len: (min = 1, max = 255, message = `长度为${min}-${max}`, trigger = ["blur", "change"]) => { | ||
20 | + return { | ||
21 | + min: min, | ||
22 | + max: max, | ||
23 | + message: message, | ||
24 | + trigger: trigger | ||
25 | + } | ||
26 | + }, | ||
27 | + // 最小长度 | ||
28 | + min: (min = 1, message = `最小长度为${min}`, trigger = ["blur", "change"]) => { | ||
29 | + return { | ||
30 | + min: min, | ||
31 | + message: message, | ||
32 | + trigger: trigger | ||
33 | + } | ||
34 | + }, | ||
35 | + // 最大长度 | ||
36 | + max: (max = 255, message = `最大长度为${max}`, trigger = ["blur", "change"]) => { | ||
37 | + return { | ||
38 | + max: max, | ||
39 | + message: message, | ||
40 | + trigger: trigger | ||
41 | + } | ||
42 | + }, | ||
43 | + // 最小数 | ||
44 | + minNum: (min = 1, type = "number", message = `不能小于${min}`, trigger = ["blur", "change"]) => { | ||
45 | + return { | ||
46 | + type: type, | ||
47 | + min: min, | ||
48 | + message: message, | ||
49 | + trigger: trigger | ||
50 | + } | ||
51 | + }, | ||
52 | + // 最大数 | ||
53 | + maxNum: (max = 255, type = "number", message = `不能大于${max}`, trigger = ["blur", "change"]) => { | ||
54 | + return { | ||
55 | + type: type, | ||
56 | + max: max, | ||
57 | + message: message, | ||
58 | + trigger: trigger | ||
59 | + } | ||
60 | + }, | ||
61 | + // 数值范围 | ||
62 | + rangeNum: (min = 1, max = 255, message = `只能输入${min}-${max}之间的数`, trigger = ["blur", "change"]) => { | ||
63 | + const validator = (rule, value, callback) => { | ||
64 | + if (value === "" || (Number(value) >= min && Number(value) <= max)) { | ||
65 | + callback() | ||
66 | + } else { | ||
67 | + callback(new Error(message)) | ||
68 | + } | ||
69 | + } | ||
70 | + return { | ||
71 | + validator, | ||
72 | + trigger | ||
73 | + } | ||
74 | + }, | ||
75 | + // 类型 | ||
76 | + type: (type = "string", message = `输入的类型必须为${type}`, trigger = ["blur", "change"]) => { | ||
77 | + return { | ||
78 | + type: type, | ||
79 | + message: message, | ||
80 | + trigger: trigger | ||
81 | + } | ||
82 | + }, | ||
83 | + | ||
84 | + password: (callback) => { | ||
85 | + return { | ||
86 | + validator: callback, | ||
87 | + trigger: "change" | ||
88 | + } | ||
89 | + }, | ||
90 | + // 邮箱 | ||
91 | + email: (message = "请输入正确的邮箱地址", trigger = ["blur", "change"]) => { | ||
92 | + // eslint-disable-next-line no-useless-escape | ||
93 | + const reg = /^[a-zA-Z0-9][a-zA-Z0-9 . _-]+(@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)+)$/ | ||
94 | + const validator = (rule, value, callback) => { | ||
95 | + if (value === "" || reg.test(value)) { | ||
96 | + callback() | ||
97 | + } else { | ||
98 | + callback(new Error(message)) | ||
99 | + } | ||
100 | + } | ||
101 | + return { | ||
102 | + validator, | ||
103 | + trigger | ||
104 | + } | ||
105 | + }, | ||
106 | + // 大写字母 | ||
107 | + upperCase: (message = "请输入大写字母", trigger = ["blur", "change"]) => { | ||
108 | + const reg = /^[A-Z]+$/ | ||
109 | + const validator = (rule, value, callback) => { | ||
110 | + if (value === "" || reg.test(value)) { | ||
111 | + callback() | ||
112 | + } else { | ||
113 | + callback(new Error(message)) | ||
114 | + } | ||
115 | + } | ||
116 | + return { | ||
117 | + validator, | ||
118 | + trigger | ||
119 | + } | ||
120 | + }, | ||
121 | + // 小写字母 | ||
122 | + lowerCase: (message = "请输入小写字母", trigger = ["blur", "change"]) => { | ||
123 | + const reg = /^[A-Z]+$/ | ||
124 | + const validator = (rule, value, callback) => { | ||
125 | + if (value === "" || reg.test(value)) { | ||
126 | + callback() | ||
127 | + } else { | ||
128 | + callback(new Error(message)) | ||
129 | + } | ||
130 | + } | ||
131 | + return { | ||
132 | + validator, | ||
133 | + trigger | ||
134 | + } | ||
135 | + }, | ||
136 | + // 大小写字母 | ||
137 | + english: (message = "请输入英文", trigger = ["blur", "change"]) => { | ||
138 | + const reg = /^[A-Za-z]+$/ | ||
139 | + const validator = (rule, value, callback) => { | ||
140 | + if (value === "" || reg.test(value)) { | ||
141 | + callback() | ||
142 | + } else { | ||
143 | + callback(new Error(message)) | ||
144 | + } | ||
145 | + } | ||
146 | + return { | ||
147 | + validator, | ||
148 | + trigger | ||
149 | + } | ||
150 | + }, | ||
151 | + // 只能输中文 | ||
152 | + chinese: (message = "请输入中文", trigger = ["blur", "change"]) => { | ||
153 | + const reg = /^[\u4e00-\u9fa5]+$/ | ||
154 | + const validator = (rule, value, callback) => { | ||
155 | + if (value === "" || reg.test(value)) { | ||
156 | + callback() | ||
157 | + } else { | ||
158 | + callback(new Error(message)) | ||
159 | + } | ||
160 | + } | ||
161 | + return { | ||
162 | + validator, | ||
163 | + trigger | ||
164 | + } | ||
165 | + }, | ||
166 | + // 不能输中文 | ||
167 | + noChinese: (message = "不能包含中文", trigger = ["blur", "change"]) => { | ||
168 | + const validator = (rule, value, callback) => { | ||
169 | + if (value === "" || escape(value).indexOf("%u") >= 0) { | ||
170 | + callback() | ||
171 | + } else { | ||
172 | + callback(new Error(message)) | ||
173 | + } | ||
174 | + } | ||
175 | + return { | ||
176 | + validator, | ||
177 | + trigger | ||
178 | + } | ||
179 | + }, | ||
180 | + // 中文英文数字 | ||
181 | + cnEnNum: (message = "请输入中文、大小写英文、数字", trigger = ["blur", "change"]) => { | ||
182 | + const reg = /^[\u4e00-\u9fa5|A-Za-z0-9]+$/ | ||
183 | + const validator = (rule, value, callback) => { | ||
184 | + if (value === "" || reg.test(value)) { | ||
185 | + callback() | ||
186 | + } else { | ||
187 | + callback(new Error(message)) | ||
188 | + } | ||
189 | + } | ||
190 | + return { | ||
191 | + validator, | ||
192 | + trigger | ||
193 | + } | ||
194 | + }, | ||
195 | + // 路径 | ||
196 | + path: (message = "请输入英文、数字、划线、斜线", trigger = ["blur", "change"]) => { | ||
197 | + const reg = /^[-|_|/|A-Za-z0-9]+$/ | ||
198 | + const validator = (rule, value, callback) => { | ||
199 | + if (value === "" || reg.test(value)) { | ||
200 | + callback() | ||
201 | + } else { | ||
202 | + callback(new Error(message)) | ||
203 | + } | ||
204 | + } | ||
205 | + return { | ||
206 | + validator, | ||
207 | + trigger | ||
208 | + } | ||
209 | + }, | ||
210 | + // 英文数字下划线 | ||
211 | + enNumLine: (message = "请输入英文、数字、下划线", trigger = ["blur", "change"]) => { | ||
212 | + const reg = /^[_|A-Za-z0-9]+$/ | ||
213 | + const validator = (rule, value, callback) => { | ||
214 | + if (value === "" || reg.test(value)) { | ||
215 | + callback() | ||
216 | + } else { | ||
217 | + callback(new Error(message)) | ||
218 | + } | ||
219 | + } | ||
220 | + return { | ||
221 | + validator, | ||
222 | + trigger | ||
223 | + } | ||
224 | + }, | ||
225 | + // 英文数字 | ||
226 | + enNum: (message = "请输入英文、数字", trigger = ["blur", "change"]) => { | ||
227 | + const reg = /^[A-Za-z0-9]+$/ | ||
228 | + const validator = (rule, value, callback) => { | ||
229 | + if (value === "" || reg.test(value)) { | ||
230 | + callback() | ||
231 | + } else { | ||
232 | + callback(new Error(message)) | ||
233 | + } | ||
234 | + } | ||
235 | + return { | ||
236 | + validator, | ||
237 | + trigger | ||
238 | + } | ||
239 | + }, | ||
240 | + // 必须包含英文数字 | ||
241 | + haveCnEnNum: (message = "必须包含英文和数字", trigger = ["blur", "change"]) => { | ||
242 | + const reg = /^(?=.*[a-zA-Z]+)(?=.*[0-9]+)[a-zA-Z0-9]+$/ | ||
243 | + const validator = (rule, value, callback) => { | ||
244 | + if (value === "" || reg.test(value)) { | ||
245 | + callback() | ||
246 | + } else { | ||
247 | + callback(new Error(message)) | ||
248 | + } | ||
249 | + } | ||
250 | + return { | ||
251 | + validator, | ||
252 | + trigger | ||
253 | + } | ||
254 | + }, | ||
255 | + // 手机号 | ||
256 | + mobile: (message = "请输入正确的手机号码", trigger = ["blur", "change"]) => { // 手机号码验证 | ||
257 | + const reg = /^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(16[2|6|7])|(18[0-9])|(17([0-1]|[3]|[5-8]))|(19[1|8|9]))\d{8}$/ | ||
258 | + const validator = (rule, value, callback) => { | ||
259 | + if (value === "" || reg.test(value)) { | ||
260 | + callback() | ||
261 | + } else { | ||
262 | + callback(new Error(message)) | ||
263 | + } | ||
264 | + } | ||
265 | + return { | ||
266 | + validator, | ||
267 | + trigger | ||
268 | + } | ||
269 | + }, | ||
270 | + // 座机 | ||
271 | + phone: (message = "请输入正确的座机号码", trigger = ["blur", "change"]) => { | ||
272 | + const reg = /^((\d{3,4}-\d{7,8})|(\d{7}-\d{1,12})|(\d{8}-\d{1,11})|(\d{11}-\d{1,8})|(\d{7,8})|(\d{11,20})|(\d{3}-\d{8}-\d{1,7})|(\d{3}-\d{7}-\d{1,8})|(\d{4}-\d{7}-\d{1,7})|(\d{4}-\d{8}-\d{1,6}))$/ | ||
273 | + const validator = (rule, value, callback) => { | ||
274 | + if (value === "" || reg.test(value)) { | ||
275 | + callback() | ||
276 | + } else { | ||
277 | + callback(new Error(message)) | ||
278 | + } | ||
279 | + } | ||
280 | + return { | ||
281 | + validator, | ||
282 | + trigger | ||
283 | + } | ||
284 | + }, | ||
285 | + // 手机或座机 | ||
286 | + phoneAll: (message = "请输入正确的电话号码", trigger = ["blur", "change"]) => { | ||
287 | + const reg = /^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(16[2|6|7])|(18[0-9])|(17([0-1]|[3]|[5-8]))|(19[1|8|9]))\d{8}$|^((\d{3,4}-\d{7,8})|(\d{7}-\d{1,12})|(\d{8}-\d{1,11})|(\d{11}-\d{1,8})|(\d{7,8})|(\d{11,20})|(\d{3}-\d{8}-\d{1,7})|(\d{3}-\d{7}-\d{1,8})|(\d{4}-\d{7}-\d{1,7})|(\d{4}-\d{8}-\d{1,6}))$/ | ||
288 | + const validator = (rule, value, callback) => { | ||
289 | + if (value === "" || reg.test(value)) { | ||
290 | + callback() | ||
291 | + } else { | ||
292 | + callback(new Error(message)) | ||
293 | + } | ||
294 | + } | ||
295 | + return { | ||
296 | + validator, | ||
297 | + trigger | ||
298 | + } | ||
299 | + }, | ||
300 | + // 小数 | ||
301 | + float: (message = "请输入合法的数字", trigger = ["blur", "change"]) => { | ||
302 | + const reg = /^[0-9]+([.]{1}[0-9]+){0,1}$/ | ||
303 | + const va = (rule, value, callback) => { | ||
304 | + if (value === null || value === "") { | ||
305 | + callback() | ||
306 | + } | ||
307 | + if (reg.test(value)) { | ||
308 | + callback() | ||
309 | + } else { | ||
310 | + callback(new Error(message)) | ||
311 | + } | ||
312 | + } | ||
313 | + return { | ||
314 | + validator: va, | ||
315 | + trigger: trigger | ||
316 | + } | ||
317 | + }, | ||
318 | + // 两位小数 | ||
319 | + decimal: (message = "请输入最多两位小数", trigger = ["blur", "change"]) => { | ||
320 | + const reg = /^(([0-9]*)|(([0]\.\d{1,2}|[0-9]*\.\d{1,2})))$/ | ||
321 | + const va = (rule, value, callback) => { | ||
322 | + if (value === null || value === "") { | ||
323 | + callback() | ||
324 | + } | ||
325 | + if (reg.test(value)) { | ||
326 | + callback() | ||
327 | + } else { | ||
328 | + callback(new Error(message)) | ||
329 | + } | ||
330 | + } | ||
331 | + return { | ||
332 | + validator: va, | ||
333 | + trigger: trigger | ||
334 | + } | ||
335 | + }, | ||
336 | + // 整数 | ||
337 | + number: (message = "请输入合法的数字", trigger = ["blur", "change"]) => { | ||
338 | + const reg = /^[0-9]\d*$/ | ||
339 | + const va = (rule, value, callback) => { | ||
340 | + if (value === "") { | ||
341 | + callback() | ||
342 | + } else if (reg.test(value)) { | ||
343 | + callback() | ||
344 | + } else { | ||
345 | + callback(new Error(message)) | ||
346 | + } | ||
347 | + } | ||
348 | + return { | ||
349 | + validator: va, | ||
350 | + trigger: trigger | ||
351 | + } | ||
352 | + }, | ||
353 | + // 正数 | ||
354 | + plusNumber: (message = "请输入合法的数字", trigger = ["blur", "change"]) => { | ||
355 | + const reg = /^(0|[1-9][0-9]*)(\.\d+)?$/ | ||
356 | + const va = (rule, value, callback) => { | ||
357 | + if (value === "") { | ||
358 | + callback() | ||
359 | + } else if (reg.test(value)) { | ||
360 | + callback() | ||
361 | + } else { | ||
362 | + callback(new Error(message)) | ||
363 | + } | ||
364 | + } | ||
365 | + return { | ||
366 | + validator: va, | ||
367 | + trigger: trigger | ||
368 | + } | ||
369 | + }, | ||
370 | + // 大于0的正数 | ||
371 | + moreThanZeroNumber: (message = "只能输入大于0的整数", trigger = ["blur", "change"]) => { | ||
372 | + const reg = /^\+?[1-9]\d*$/ | ||
373 | + const va = (rule, value, callback) => { | ||
374 | + if (value === "") { | ||
375 | + callback() | ||
376 | + } else if (reg.test(value)) { | ||
377 | + callback() | ||
378 | + } else { | ||
379 | + callback(new Error(message)) | ||
380 | + } | ||
381 | + } | ||
382 | + return { | ||
383 | + validator: va, | ||
384 | + trigger: trigger | ||
385 | + } | ||
386 | + }, | ||
387 | + // 网址 | ||
388 | + url: (message = "请输入正确的网址", trigger = ["blur", "change"]) => { | ||
389 | + const reg = /^(?=^.{3,255}$)(http(s)?:\/\/)?(www\.)?[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+(:\d+)*(\/\w+\.\w+)*$/ | ||
390 | + const va = (rule, value, callback) => { | ||
391 | + if (value === "") { | ||
392 | + callback() | ||
393 | + } | ||
394 | + if (reg.test(value)) { | ||
395 | + callback() | ||
396 | + } else { | ||
397 | + callback(new Error(message)) | ||
398 | + } | ||
399 | + } | ||
400 | + return { | ||
401 | + validator: va, | ||
402 | + trigger: trigger | ||
403 | + } | ||
404 | + }, | ||
405 | + // ip地址 | ||
406 | + ip: (message = "请输入正确的ip", trigger = ["blur", "change"]) => { | ||
407 | + const reg = /^(?=(\b|\D))(((\d{1,2})|(1\d{1,2})|(2[0-4]\d)|(25[0-5]))\.){3}((\d{1,2})|(1\d{1,2})|(2[0-4]\d)|(25[0-5]))(?=(\b|\D))*$/ | ||
408 | + const va = (rule, value, callback) => { | ||
409 | + if (value === "") { | ||
410 | + callback() | ||
411 | + } | ||
412 | + if (reg.test(value)) { | ||
413 | + callback() | ||
414 | + } else { | ||
415 | + callback(new Error(message)) | ||
416 | + } | ||
417 | + } | ||
418 | + return { | ||
419 | + validator: va, | ||
420 | + trigger: trigger | ||
421 | + } | ||
422 | + }, | ||
423 | + // 身份证号 | ||
424 | + identity: (message = "请输入正确的身份证号", trigger = ["blur", "change"]) => { | ||
425 | + const reg = /^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X|x)$/ | ||
426 | + // ^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{2}$ | ||
427 | + const va = (rule, value, callback) => { | ||
428 | + if (value === "") { | ||
429 | + callback() | ||
430 | + } | ||
431 | + if (reg.test(value)) { | ||
432 | + callback() | ||
433 | + } else { | ||
434 | + callback(new Error(message)) | ||
435 | + } | ||
436 | + } | ||
437 | + return { | ||
438 | + validator: va, | ||
439 | + trigger: trigger | ||
440 | + } | ||
441 | + }, | ||
442 | + // 邮政编码 | ||
443 | + postal: (message = "请输入正确的邮政编码", trigger = ["blur", "change"]) => { | ||
444 | + const reg = /^\d{6}$/ | ||
445 | + const va = (rule, value, callback) => { | ||
446 | + if (value === "") { | ||
447 | + callback() | ||
448 | + } | ||
449 | + if (reg.test(value)) { | ||
450 | + callback() | ||
451 | + } else { | ||
452 | + callback(new Error(message)) | ||
453 | + } | ||
454 | + } | ||
455 | + return { | ||
456 | + validator: va, | ||
457 | + trigger: trigger | ||
458 | + } | ||
459 | + } | ||
460 | +} | ||
461 | + |
src/views/commerViews.vue
0 → 100644
src/views/duoji/erji.vue
0 → 100644
src/views/duoji/sanji.vue
0 → 100644
src/views/duoji/siji.vue
0 → 100644
src/views/index/mainIndex.vue
0 → 100644
1 | +<template> | ||
2 | + <el-row> | ||
3 | + <el-col :span="24"> | ||
4 | + <line-echarts | ||
5 | + id="lineEcharts" | ||
6 | + height="300px" | ||
7 | + ref="echarts" | ||
8 | + ></line-echarts> | ||
9 | + </el-col> | ||
10 | + </el-row> | ||
11 | +</template> | ||
12 | + | ||
13 | +<script> | ||
14 | +import LineEcharts from "components/ECharts/lineEcharts"; | ||
15 | +export default { | ||
16 | + name: "mainIndex", | ||
17 | + components: { LineEcharts }, | ||
18 | + mounted() { | ||
19 | + this.selfAdaption(); | ||
20 | + }, | ||
21 | + methods: { | ||
22 | + // echart自适应 | ||
23 | + selfAdaption() { | ||
24 | + let that = this; | ||
25 | + setTimeout(() => { | ||
26 | + window.onresize = function () { | ||
27 | + if (that.$refs.echarts) { | ||
28 | + that.$refs.echarts.chart.resize(); | ||
29 | + } | ||
30 | + }; | ||
31 | + }, 10); | ||
32 | + }, | ||
33 | + }, | ||
34 | +}; | ||
35 | +</script> | ||
36 | + | ||
37 | +<style lang="scss"> | ||
38 | +$top: top; | ||
39 | +$bottom: bottom; | ||
40 | +$left: left; | ||
41 | +$right: right; | ||
42 | +$leftright: ($left, $right); | ||
43 | +$pinkk: #eec2d3; | ||
44 | +$bluee: #409eff; | ||
45 | +$yelloww: #f4d884; | ||
46 | +$grennn: #89dda0; | ||
47 | +$purplee: #78a2ea; | ||
48 | +$lightBluee: #b8d6ff; | ||
49 | + | ||
50 | +$list: bluee pinkk yelloww grennn purplee lightBluee; | ||
51 | +$list1: $bluee $pinkk $yelloww $grennn $purplee $lightBluee; | ||
52 | +%shadow { | ||
53 | + background: #fff; | ||
54 | + -webkit-box-shadow: 4px 4px 40px rgba(0, 0, 0, 0.2); | ||
55 | + box-shadow: 4px 4px 40px rgba(0, 0, 0, 0.2); | ||
56 | + border-color: rgba(0, 0, 0, 0.2); | ||
57 | + .title { | ||
58 | + font-size: 14px; | ||
59 | + padding: 10px; | ||
60 | + i { | ||
61 | + margin-#{$right}: 5px; | ||
62 | + } | ||
63 | + } | ||
64 | +} | ||
65 | + | ||
66 | +@mixin flex($direction: row, $content: space-between) { | ||
67 | + display: flex; | ||
68 | + flex-direction: $direction; | ||
69 | + justify-content: $content; | ||
70 | +} | ||
71 | +.card { | ||
72 | + color: #666; | ||
73 | + @extend %shadow; | ||
74 | + | ||
75 | + ul { | ||
76 | + @include flex; | ||
77 | + li { | ||
78 | + flex: 1; | ||
79 | + a { | ||
80 | + color: #666666; | ||
81 | + align-items: center; | ||
82 | + padding-#{$top}: 20px; | ||
83 | + padding-#{$bottom}: 20px; | ||
84 | + @include flex(column); | ||
85 | + span { | ||
86 | + height: 44px; | ||
87 | + } | ||
88 | + .num { | ||
89 | + line-height: 44px; | ||
90 | + font-size: 42px; | ||
91 | + color: $bluee; | ||
92 | + margin: 0px; | ||
93 | + } | ||
94 | + } | ||
95 | + .kjfs-bluee { | ||
96 | + color: $bluee; | ||
97 | + } | ||
98 | + .kjfs-pinkk { | ||
99 | + color: $pinkk; | ||
100 | + } | ||
101 | + .kjfs-yelloww { | ||
102 | + color: $yelloww; | ||
103 | + } | ||
104 | + .kjfs-grennn { | ||
105 | + color: $grennn; | ||
106 | + } | ||
107 | + .kjfs-purplee { | ||
108 | + color: $purplee; | ||
109 | + } | ||
110 | + .kjfs-lightBluee { | ||
111 | + color: $lightBluee; | ||
112 | + } | ||
113 | + &:hover { | ||
114 | + .kjfs-bluee { | ||
115 | + color: #ffffff; | ||
116 | + background: $bluee; | ||
117 | + } | ||
118 | + .kjfs-pinkk { | ||
119 | + color: #ffffff; | ||
120 | + background: $pinkk; | ||
121 | + } | ||
122 | + .kjfs-yelloww { | ||
123 | + color: #ffffff; | ||
124 | + background: $yelloww; | ||
125 | + } | ||
126 | + .kjfs-grennn { | ||
127 | + color: #ffffff; | ||
128 | + background: $grennn; | ||
129 | + } | ||
130 | + .kjfs-purplee { | ||
131 | + color: #ffffff; | ||
132 | + background: $purplee; | ||
133 | + } | ||
134 | + .kjfs-lightBluee { | ||
135 | + color: #ffffff; | ||
136 | + background: $lightBluee; | ||
137 | + } | ||
138 | + } | ||
139 | + } | ||
140 | + } | ||
141 | +} | ||
142 | +#lineEcharts { | ||
143 | + margin-#{$top}: 30px; | ||
144 | + padding-#{$top}: 30px; | ||
145 | + @extend %shadow; | ||
146 | +} | ||
147 | +</style> |
src/views/layout/Footer/bottom.vue
0 → 100644
1 | +<template> | ||
2 | + <div> | ||
3 | + <p>Copyright © 2022 guoke</p> | ||
4 | + </div> | ||
5 | +</template> | ||
6 | + | ||
7 | +<script> | ||
8 | +export default { | ||
9 | + name: "bottom" | ||
10 | +} | ||
11 | +</script> | ||
12 | + | ||
13 | +<style scoped> | ||
14 | +p{ | ||
15 | + height: 28px; | ||
16 | + line-height: 28px; | ||
17 | + text-align: left; | ||
18 | + font-size: 12px; | ||
19 | + color: #999999; | ||
20 | +} | ||
21 | +</style> |
src/views/layout/aside/aside.vue
0 → 100644
1 | +<template> | ||
2 | + <div> | ||
3 | + <el-aside id="asideNav"> | ||
4 | + <div class="logo-name"> | ||
5 | + <p v-if="$store.getters.logoShow">XU</p> | ||
6 | + <p v-else>admin</p> | ||
7 | + </div> | ||
8 | + <el-menu | ||
9 | + :default-active="$route.path" | ||
10 | + class="el-menu-vertical" | ||
11 | + @select="selectmenu" | ||
12 | + :collapse="$store.getters.isCollapse" | ||
13 | + background-color="#03152A" | ||
14 | + text-color="rgba(255,255,255,.7)" | ||
15 | + active-text-color="#ffffff" | ||
16 | + :router="$store.getters.uniquerouter" | ||
17 | + :unique-opened="$store.getters.uniquerouter" | ||
18 | + :collapse-transition="true" | ||
19 | + > | ||
20 | + <template v-for="(item, index) in $store.getters.routers"> | ||
21 | + <template v-if="!item.hidden"> | ||
22 | + <el-submenu | ||
23 | + v-if="!item.alone && item.children.length > 0" | ||
24 | + :index="index + ''" | ||
25 | + :key="index" | ||
26 | + > | ||
27 | + <template slot="title"> | ||
28 | + <i :class="item.iconCls ? item.iconCls : [fa, fa - server]"></i> | ||
29 | + <span slot="title">{{item.name}}</span> | ||
30 | + </template> | ||
31 | + | ||
32 | + <menu-tree :menuData="item.children"></menu-tree> | ||
33 | + </el-submenu> | ||
34 | + <el-menu-item :index="item.path" v-else :key="item.path"> | ||
35 | + <i :class="item.iconCls ? item.iconCls : [fa, fa - file]" /> | ||
36 | + <span slot="title">{{ item.name }}</span> | ||
37 | + </el-menu-item> | ||
38 | + </template> | ||
39 | + </template> | ||
40 | + </el-menu> | ||
41 | + </el-aside> | ||
42 | + </div> | ||
43 | +</template> | ||
44 | + | ||
45 | +<script> | ||
46 | +import menuTree from "./menuTree"; | ||
47 | + | ||
48 | +export default { | ||
49 | + name: "asideNav", | ||
50 | + components: { | ||
51 | + menuTree, | ||
52 | + }, | ||
53 | + watch: { | ||
54 | + // 监听浏览器直接输入路由,将此路由添加到tabnavBox | ||
55 | + "$route.path": function (val) { | ||
56 | + this.selectmenu(val); | ||
57 | + }, | ||
58 | + }, | ||
59 | + methods: { | ||
60 | + selectmenu(key, indexpath) { | ||
61 | + // 如果不使用 elemenUI 菜单的 vue-router 的模式将用以下方式进行页面跳转 el-menu的router设置为false | ||
62 | + // this.$router.push(indexpath.join("/")) | ||
63 | + let router = this.$store.getters.routers; | ||
64 | + let name = ""; | ||
65 | + let navTitle = function (path, routerARR) { | ||
66 | + for (let i = 0; i < routerARR.length; i++) { | ||
67 | + if (routerARR[i].children.length > 0 || routerARR[i].path === path) { | ||
68 | + if ( | ||
69 | + routerARR[i].path === path && | ||
70 | + routerARR[i].children.length < 1 | ||
71 | + ) { | ||
72 | + name = routerARR[i].name; | ||
73 | + break; | ||
74 | + } | ||
75 | + navTitle(path, routerARR[i].children); | ||
76 | + } | ||
77 | + } | ||
78 | + return name; | ||
79 | + }; | ||
80 | + this.$store.dispatch("addTab", { | ||
81 | + title: navTitle(key, router), | ||
82 | + path: key, | ||
83 | + }); | ||
84 | + }, | ||
85 | + }, | ||
86 | +}; | ||
87 | +</script> | ||
88 | + | ||
89 | +<style lang="scss"> | ||
90 | +$top: top; | ||
91 | +$bottom: bottom; | ||
92 | +$left: left; | ||
93 | +$right: right; | ||
94 | +%w100 { | ||
95 | + width: 100%; | ||
96 | +} | ||
97 | + | ||
98 | +%h100 { | ||
99 | + height: 100%; | ||
100 | +} | ||
101 | + | ||
102 | +%cursor { | ||
103 | + cursor: pointer; | ||
104 | +} | ||
105 | + | ||
106 | +@mixin set-value($side, $value) { | ||
107 | + @each $prop in $leftright { | ||
108 | + #{$side}-#{$prop}: $value; | ||
109 | + } | ||
110 | +} | ||
111 | + | ||
112 | +#asideNav { | ||
113 | + width: auto !important; | ||
114 | + display: flex; | ||
115 | + flex-direction: column; | ||
116 | + border-right: solid 1px #e6e6e6; | ||
117 | + .logo-name { | ||
118 | + background-color: #03152a !important; | ||
119 | + @extend %w100; | ||
120 | + font-weight: 300; | ||
121 | + z-index: 999; | ||
122 | + p { | ||
123 | + height: 50px; | ||
124 | + line-height: 50px; | ||
125 | + text-align: center; | ||
126 | + font-size: 16px; | ||
127 | + color: #5e6d82; | ||
128 | + } | ||
129 | + } | ||
130 | + .el-menu-vertical:not(.el-menu--collapse) { | ||
131 | + width: 200px; | ||
132 | + @extend %h100; | ||
133 | + overflow-y: scroll; | ||
134 | + overflow-x: hidden; | ||
135 | + } | ||
136 | + .el-menu { | ||
137 | + flex: 1; | ||
138 | + overflow: inherit; | ||
139 | + border-right: none; | ||
140 | + &::-webkit-scrollbar { | ||
141 | + display: none; | ||
142 | + } | ||
143 | + .fa { | ||
144 | + vertical-align: middle; | ||
145 | + margin-right: 5px; | ||
146 | + width: 24px; | ||
147 | + text-align: center; | ||
148 | + font-size: 18px; | ||
149 | + } | ||
150 | + .el-menu-item { | ||
151 | + background-color: #020f1d !important; | ||
152 | + border-bottom: 1px solid #020f1d; | ||
153 | + &:hover { | ||
154 | + color: #ffffff !important; | ||
155 | + background-color: #375573 !important; | ||
156 | + } | ||
157 | + } | ||
158 | + .el-menu-item.is-active { | ||
159 | + background-color: #56a9ff !important; | ||
160 | + } | ||
161 | + .is-opened > .el-submenu__title > .el-icon-arrow-down { | ||
162 | + color: #ffffff; | ||
163 | + font-weight: 500; | ||
164 | + font-size: 18px; | ||
165 | + } | ||
166 | + } | ||
167 | +} | ||
168 | +</style> |
src/views/layout/aside/menuTree.vue
0 → 100644
1 | +<template> | ||
2 | + <div> | ||
3 | + <template v-for="(child) in menuData"> | ||
4 | + <el-submenu v-if="child.children.length > 0" :index="child.path" :key="child.path"> | ||
5 | + <template slot="title"> | ||
6 | + <i :class="child.iconCls?child.iconCls:[fa,fa-file]"/> | ||
7 | + <span slot="title">{{ child.name }}</span> | ||
8 | + </template> | ||
9 | + <menu-tree :menuData="child.children"/> | ||
10 | + </el-submenu> | ||
11 | + | ||
12 | + <el-menu-item v-else-if="!child.hidden" :index="child.path" :key="child.path"> | ||
13 | + <i :class="child.iconCls?child.iconCls:[fa,fa-file]"/> | ||
14 | + <span slot="title">{{ child.name}}</span> | ||
15 | + </el-menu-item> | ||
16 | + </template> | ||
17 | + </div> | ||
18 | +</template> | ||
19 | + | ||
20 | +<script> | ||
21 | +export default { | ||
22 | + name: "menuTree", | ||
23 | + props: ["menuData"] | ||
24 | +} | ||
25 | +</script> | ||
26 | + | ||
27 | +<style scoped> | ||
28 | + | ||
29 | +</style> |
src/views/layout/header/header.vue
0 → 100644
1 | +<template> | ||
2 | + <div> | ||
3 | + <el-header id="header"> | ||
4 | + <span class="hideAside" @click="collapse" | ||
5 | + ><i class="fa fa-indent fa-lg"></i | ||
6 | + ></span> | ||
7 | + <ul class="personal"> | ||
8 | + <li class="fullScreen" @click="fullScreen"> | ||
9 | + <el-tooltip | ||
10 | + class="item" | ||
11 | + effect="dark" | ||
12 | + content="全屏" | ||
13 | + placement="bottom" | ||
14 | + ><i class="fa fa-arrows-alt fa-lg"></i | ||
15 | + ></el-tooltip> | ||
16 | + </li> | ||
17 | + <!-- <li> | ||
18 | + <langSelect></langSelect> | ||
19 | + </li> --> | ||
20 | + <li>{{ $t(`role.${this.$store.getters.info.role}`) }}</li> | ||
21 | + <li> | ||
22 | + <el-dropdown @command="handleCommand"> | ||
23 | + <span class="el-dropdown-link"> | ||
24 | + {{ $t(`${this.$store.getters.info.name}`) }}<i class="el-icon-arrow-down el-icon--right"></i> | ||
25 | + </span> | ||
26 | + <el-dropdown-menu slot="dropdown"> | ||
27 | + <el-dropdown-item command="info">{{ | ||
28 | + $t("userDropdownMenu.basicInfor") | ||
29 | + }}</el-dropdown-item> | ||
30 | + <el-dropdown-item command="editPassword">{{ | ||
31 | + $t("userDropdownMenu.changePassword") | ||
32 | + }}</el-dropdown-item> | ||
33 | + <el-dropdown-item command="logout" divided>{{ | ||
34 | + $t("userDropdownMenu.logout") | ||
35 | + }}</el-dropdown-item> | ||
36 | + </el-dropdown-menu> | ||
37 | + </el-dropdown> | ||
38 | + </li> | ||
39 | + <li class="icon"><img :src="avatar" /></li> | ||
40 | + </ul> | ||
41 | + </el-header> | ||
42 | + <!-- <tabNav></tabNav> --> | ||
43 | + </div> | ||
44 | +</template> | ||
45 | + | ||
46 | +<script> | ||
47 | +import Cookies from "js-cookie"; | ||
48 | +import langSelect from "../../../components/lang/langSelect"; | ||
49 | +import tabNav from "./tabNav"; | ||
50 | +import UserInfo from "../../../components/userForm/userInfo"; | ||
51 | +import EditPassword from "../../../components/userForm/editPassword"; | ||
52 | + | ||
53 | +export default { | ||
54 | + name: "Header", | ||
55 | + components: { EditPassword, tabNav, langSelect, UserInfo }, | ||
56 | + data() { | ||
57 | + return { | ||
58 | + isfullScreen: true, | ||
59 | + avatar: require("@/assets/images/womandefault.png"), | ||
60 | + dialogInfoVisible: false, | ||
61 | + dialogPassVisible: false, | ||
62 | + title: "", | ||
63 | + userId: "", | ||
64 | + }; | ||
65 | + }, | ||
66 | + methods: { | ||
67 | + collapse() { | ||
68 | + this.$store.dispatch("collapse"); | ||
69 | + }, | ||
70 | + successCallback() { | ||
71 | + this.dialogInfoVisible = false; | ||
72 | + }, | ||
73 | + editPwdCallback() { | ||
74 | + this.dialogPassVisible = false; | ||
75 | + }, | ||
76 | + fullScreen() { | ||
77 | + if (this.isfullScreen) { | ||
78 | + var docElm = document.documentElement; | ||
79 | + if (docElm.requestFullscreen) { | ||
80 | + docElm.requestFullscreen(); | ||
81 | + } else if (docElm.mozRequestFullScreen) { | ||
82 | + docElm.mozRequestFullScreen(); | ||
83 | + } else if (docElm.webkitRequestFullScreen) { | ||
84 | + docElm.webkitRequestFullScreen(); | ||
85 | + } else if (elem.msRequestFullscreen) { | ||
86 | + elem.msRequestFullscreen(); | ||
87 | + } | ||
88 | + this.isfullScreen = false; | ||
89 | + } else { | ||
90 | + if (document.exitFullscreen) { | ||
91 | + document.exitFullscreen(); | ||
92 | + } else if (document.mozCancelFullScreen) { | ||
93 | + document.mozCancelFullScreen(); | ||
94 | + } else if (document.webkitCancelFullScreen) { | ||
95 | + document.webkitCancelFullScreen(); | ||
96 | + } else if (document.msExitFullscreen) { | ||
97 | + document.msExitFullscreen(); | ||
98 | + } | ||
99 | + this.isfullScreen = true; | ||
100 | + } | ||
101 | + }, | ||
102 | + handleCommand(command) { | ||
103 | + if (command === "info") { | ||
104 | + this.dialogInfoVisible = true; | ||
105 | + this.title = "编辑信息"; | ||
106 | + // this.userId = this.$store.getters.info.uid | ||
107 | + } else if (command === "editPassword") { | ||
108 | + this.dialogPassVisible = true; | ||
109 | + } else if (command === "logout") { | ||
110 | + Cookies.remove("token"); | ||
111 | + location.reload(); | ||
112 | + } | ||
113 | + }, | ||
114 | + }, | ||
115 | +}; | ||
116 | +</script> | ||
117 | + | ||
118 | +<style lang="scss"> | ||
119 | +$top: top; | ||
120 | +$bottom: bottom; | ||
121 | +$left: left; | ||
122 | +$right: right; | ||
123 | +$leftright: ($left, $right); | ||
124 | +%w100 { | ||
125 | + width: 100%; | ||
126 | +} | ||
127 | + | ||
128 | +%h100 { | ||
129 | + height: 100%; | ||
130 | +} | ||
131 | + | ||
132 | +%cursor { | ||
133 | + cursor: pointer; | ||
134 | +} | ||
135 | + | ||
136 | +html, | ||
137 | +body, | ||
138 | +#app, | ||
139 | +.el-container, | ||
140 | +#asideNav, | ||
141 | +ul.el-menu { | ||
142 | + @extend %h100; | ||
143 | +} | ||
144 | + | ||
145 | +@mixin set-value($side, $value) { | ||
146 | + @each $prop in $leftright { | ||
147 | + #{$side}-#{$prop}: $value; | ||
148 | + } | ||
149 | +} | ||
150 | + | ||
151 | +#header { | ||
152 | + max-height: 50px; | ||
153 | + line-height: 50px; | ||
154 | + box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); | ||
155 | + display: flex; | ||
156 | + justify-content: space-between; | ||
157 | + .hideAside { | ||
158 | + @extend %cursor; | ||
159 | + } | ||
160 | + .personal { | ||
161 | + display: flex; | ||
162 | + flex-direction: row; | ||
163 | + li { | ||
164 | + @include set-value(margin, 13px); | ||
165 | + font-size: 12px; | ||
166 | + } | ||
167 | + .fullScreen { | ||
168 | + @extend %cursor; | ||
169 | + } | ||
170 | + .el-dropdown-link { | ||
171 | + @extend %cursor; | ||
172 | + } | ||
173 | + .icon img { | ||
174 | + margin-#{$top}: 7px; | ||
175 | + -webkit-border-radius: 5px; | ||
176 | + -moz-border-radius: 5px; | ||
177 | + border-radius: 5px; | ||
178 | + width: 40px; | ||
179 | + height: 40px; | ||
180 | + } | ||
181 | + } | ||
182 | +} | ||
183 | +</style> |
src/views/layout/header/tabNav.vue
0 → 100644
1 | +<template> | ||
2 | + <div> | ||
3 | + <div class="tabnavBox"> | ||
4 | + <transition-group name="list" tag="ul"> | ||
5 | + <li | ||
6 | + v-for="(item, index) in $store.getters.tabnavBox" | ||
7 | + :key="item.path" | ||
8 | + @contextmenu.prevent="openMenu(item, $event, index)" | ||
9 | + class="tabnav" | ||
10 | + :class="{ active: $route.path === item.path }" | ||
11 | + > | ||
12 | + <router-link :to="item.path">{{ | ||
13 | + $t(`routeName.${item.title}`) | ||
14 | + }}</router-link> | ||
15 | + <i | ||
16 | + @click="removeTab(item)" | ||
17 | + class="el-icon-error" | ||
18 | + v-if="index !== 0" | ||
19 | + ></i> | ||
20 | + </li> | ||
21 | + </transition-group> | ||
22 | + </div> | ||
23 | + <ul | ||
24 | + v-show="this.rightMenuShow" | ||
25 | + :style="{ left: this.left + 'px', top: this.top + 'px' }" | ||
26 | + class="menuBox" | ||
27 | + > | ||
28 | + <li @click="removeTab($store.getters.rightNav)"> | ||
29 | + <i class="fa fa-remove"></i>{{ $t("rightMenu.close") }} | ||
30 | + </li> | ||
31 | + <li @click="removeOtherTab($store.getters.rightNav)"> | ||
32 | + {{ $t("rightMenu.closeOther") }} | ||
33 | + </li> | ||
34 | + <li @click="removeAllTab">{{ $t("rightMenu.closeAll") }}</li> | ||
35 | + </ul> | ||
36 | + </div> | ||
37 | +</template> | ||
38 | + | ||
39 | +<script> | ||
40 | +export default { | ||
41 | + name: "tabNav", | ||
42 | + data() { | ||
43 | + return { | ||
44 | + rightMenuShow: false, | ||
45 | + left: 0, | ||
46 | + top: 0, | ||
47 | + }; | ||
48 | + }, | ||
49 | + methods: { | ||
50 | + openMenu(item, e, index) { | ||
51 | + if (index === 0) { | ||
52 | + return false; | ||
53 | + } | ||
54 | + this.rightMenuShow = true; | ||
55 | + this.left = e.clientX + 10; | ||
56 | + this.top = e.clientY; | ||
57 | + this.$store.dispatch("openMenu", item); | ||
58 | + }, | ||
59 | + removeTab(tabItem) { | ||
60 | + this.$store.dispatch("removeTab", { | ||
61 | + tabItem, | ||
62 | + fullPath: this.$route.fullPath, | ||
63 | + router: this.$router, | ||
64 | + }); | ||
65 | + }, | ||
66 | + removeOtherTab(tabItem) { | ||
67 | + this.$store.dispatch("removeOtherTab", { tabItem, router: this.$router }); | ||
68 | + }, | ||
69 | + removeAllTab() { | ||
70 | + this.$store.dispatch("removeOtherTab", { | ||
71 | + all: true, | ||
72 | + router: this.$router, | ||
73 | + }); | ||
74 | + }, | ||
75 | + }, | ||
76 | + watch: { | ||
77 | + rightMenuShow(value) { | ||
78 | + if (value) { | ||
79 | + document.body.addEventListener("click", () => { | ||
80 | + this.rightMenuShow = false; | ||
81 | + }); | ||
82 | + } else { | ||
83 | + document.body.removeEventListener("click", () => { | ||
84 | + this.rightMenuShow = false; | ||
85 | + }); | ||
86 | + } | ||
87 | + }, | ||
88 | + }, | ||
89 | +}; | ||
90 | +</script> | ||
91 | +<style> | ||
92 | +.tabnav { | ||
93 | + display: inline-block; | ||
94 | + transition: all 0.5s; | ||
95 | +} | ||
96 | + | ||
97 | +.list-enter, | ||
98 | +.list-leave-to { | ||
99 | + opacity: 0; | ||
100 | + transform: translateY(30px); | ||
101 | +} | ||
102 | + | ||
103 | +.list-enter-active { | ||
104 | + transition: all 0.5s; | ||
105 | +} | ||
106 | + | ||
107 | +.list-leave-active { | ||
108 | + position: absolute; | ||
109 | + transition: all 1s; | ||
110 | +} | ||
111 | +</style> | ||
112 | +<style lang="scss"> | ||
113 | +$top: top; | ||
114 | +$bottom: bottom; | ||
115 | +$left: left; | ||
116 | +$right: right; | ||
117 | +$leftright: ($left, $right); | ||
118 | + | ||
119 | +%w100 { | ||
120 | + width: 100%; | ||
121 | +} | ||
122 | + | ||
123 | +%h100 { | ||
124 | + height: 100%; | ||
125 | +} | ||
126 | + | ||
127 | +%cursor { | ||
128 | + cursor: pointer; | ||
129 | +} | ||
130 | + | ||
131 | +@mixin set-value($side, $value) { | ||
132 | + @each $prop in $leftright { | ||
133 | + #{$side}-#{$prop}: $value; | ||
134 | + } | ||
135 | +} | ||
136 | + | ||
137 | +.tabnavBox { | ||
138 | + @extend %w100; | ||
139 | + height: 36px; | ||
140 | + min-height: 36px; | ||
141 | + overflow: hidden; | ||
142 | + border-#{$top}: 1px solid #f6f6f6; | ||
143 | + border-#{$bottom}: 1px solid #d8dce5; | ||
144 | + | ||
145 | + -webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), | ||
146 | + 0 0 3px 0 rgba(0, 0, 0, 0.04); | ||
147 | + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04); | ||
148 | + ul { | ||
149 | + display: flex; | ||
150 | + justify-content: flex-start; | ||
151 | + padding-#{$left}: 20px; | ||
152 | + flex-wrap: nowrap; | ||
153 | + overflow-x: auto; | ||
154 | + li { | ||
155 | + line-height: 22px; | ||
156 | + display: flex; | ||
157 | + align-items: center; | ||
158 | + @extend %cursor; | ||
159 | + margin-#{$top}: 6px; | ||
160 | + margin-#{$right}: 5px; | ||
161 | + border:1px solid #e2e2e2; | ||
162 | + box-sizing: border-box; | ||
163 | + overflow: hidden; | ||
164 | + &:not(:first-child) { | ||
165 | + padding-#{$right}: 10px; | ||
166 | + min-width: 80px; | ||
167 | + } | ||
168 | + a { | ||
169 | + @include set-value(padding, 10px); | ||
170 | + display: inline-block; | ||
171 | + @extend %h100; | ||
172 | + font-size: 12px; | ||
173 | + color: #999999; | ||
174 | + } | ||
175 | + &:nth-child(n + 2) { | ||
176 | + a { | ||
177 | + padding-#{$right}: 15px; | ||
178 | + } | ||
179 | + } | ||
180 | + i { | ||
181 | + @extend %cursor; | ||
182 | + &:hover { | ||
183 | + color: red; | ||
184 | + } | ||
185 | + } | ||
186 | + } | ||
187 | + li.active { | ||
188 | + line-height: 24px; | ||
189 | + background: #409eff; | ||
190 | + color: #ffffff; | ||
191 | + border:none; | ||
192 | + a { | ||
193 | + color: #ffffff; | ||
194 | + } | ||
195 | + } | ||
196 | + } | ||
197 | +} | ||
198 | + | ||
199 | +.menuBox { | ||
200 | + margin: 0; | ||
201 | + background: #fff; | ||
202 | + z-index: 999; | ||
203 | + position: absolute; | ||
204 | + padding: 5px 0; | ||
205 | + border: 1px solid #cccccc; | ||
206 | + font-size: 12px; | ||
207 | + font-weight: 400; | ||
208 | + color: #333; | ||
209 | + box-shadow: 2px 1px 6px 0 rgba(0, 0, 0, 0.3); | ||
210 | + li { | ||
211 | + margin: 0; | ||
212 | + padding: 7px 16px; | ||
213 | + @extend %cursor; | ||
214 | + &:hover { | ||
215 | + background: #e1e6ea; | ||
216 | + } | ||
217 | + } | ||
218 | +} | ||
219 | +</style> |
src/views/layout/layout.vue
0 → 100644
1 | +<template> | ||
2 | + <div id="loyout"> | ||
3 | + <el-container> | ||
4 | + <layoutAside></layoutAside> | ||
5 | + <el-container> | ||
6 | + <layoutHeader></layoutHeader> | ||
7 | + <el-main id="elmain"> | ||
8 | + <transition name="main" mode="out-in"> | ||
9 | + <router-view></router-view> | ||
10 | + </transition> | ||
11 | + </el-main> | ||
12 | + <el-footer height="28px"> | ||
13 | + <Bottom></Bottom> | ||
14 | + </el-footer> | ||
15 | + </el-container> | ||
16 | + </el-container> | ||
17 | + </div> | ||
18 | +</template> | ||
19 | + | ||
20 | +<script> | ||
21 | +import layoutAside from "./aside/aside"; | ||
22 | +import layoutHeader from "./header/header"; | ||
23 | +import Bottom from "./Footer/bottom"; | ||
24 | +import langSelect from "../../components/lang/langSelect"; | ||
25 | + | ||
26 | +export default { | ||
27 | + name: "layout", | ||
28 | + components: { | ||
29 | + layoutHeader, | ||
30 | + Bottom, | ||
31 | + langSelect, | ||
32 | + layoutAside, | ||
33 | + }, | ||
34 | +}; | ||
35 | +</script> | ||
36 | + | ||
37 | +<style> | ||
38 | +.main-enter, | ||
39 | +.main-leave-to { | ||
40 | + opacity: 0; | ||
41 | + transform: translateY(30px); | ||
42 | +} | ||
43 | +.main-enter-active { | ||
44 | + transition: all 0.2s; | ||
45 | +} | ||
46 | +.main-leave-active { | ||
47 | + position: absolute; | ||
48 | + transition: all 0.3s; | ||
49 | +} | ||
50 | +</style> | ||
51 | +<style lang="scss"> | ||
52 | +* { | ||
53 | + margin: 0px; | ||
54 | + padding: 0px; | ||
55 | +} | ||
56 | + | ||
57 | +body { | ||
58 | + background-color: #f2f2f2; | ||
59 | + font-size: 14px; | ||
60 | + color: #333333; | ||
61 | +} | ||
62 | + | ||
63 | +li { | ||
64 | + list-style: none; | ||
65 | +} | ||
66 | + | ||
67 | +a { | ||
68 | + text-decoration: none; | ||
69 | +} | ||
70 | + | ||
71 | +$top: top; | ||
72 | +$bottom: bottom; | ||
73 | +$left: left; | ||
74 | +$right: right; | ||
75 | +$leftright: ($left, $right); | ||
76 | +%w100 { | ||
77 | + width: 100%; | ||
78 | +} | ||
79 | + | ||
80 | +%h100 { | ||
81 | + height: 100%; | ||
82 | +} | ||
83 | + | ||
84 | +%cursor { | ||
85 | + cursor: pointer; | ||
86 | +} | ||
87 | +html, | ||
88 | +body { | ||
89 | + overflow: hidden; | ||
90 | +} | ||
91 | +html, | ||
92 | +body, | ||
93 | +#loyout, | ||
94 | +.el-container, | ||
95 | +#asideNav, | ||
96 | +ul.el-menu { | ||
97 | + @extend %h100; | ||
98 | +} | ||
99 | + | ||
100 | +@mixin set-value($side, $value) { | ||
101 | + @each $prop in $leftright { | ||
102 | + #{$side}-#{$prop}: $value; | ||
103 | + } | ||
104 | +} | ||
105 | + | ||
106 | +#elmain { | ||
107 | + background-color: #f0f2f5; | ||
108 | +} | ||
109 | + | ||
110 | +.avatar-uploader .el-upload { | ||
111 | + border: 1px dashed #d9d9d9 !important; | ||
112 | + border-radius: 6px; | ||
113 | + cursor: pointer; | ||
114 | + position: relative; | ||
115 | + overflow: hidden; | ||
116 | +} | ||
117 | +.avatar-uploader .el-upload:hover { | ||
118 | + border-color: #409eff; | ||
119 | +} | ||
120 | +.avatar-uploader-icon { | ||
121 | + font-size: 28px; | ||
122 | + color: #8c939d; | ||
123 | + width: 178px; | ||
124 | + height: 178px; | ||
125 | + line-height: 178px; | ||
126 | + text-align: center; | ||
127 | +} | ||
128 | +.avatar { | ||
129 | + width: 178px; | ||
130 | + height: 178px; | ||
131 | + display: block; | ||
132 | +} | ||
133 | +</style> |
src/views/login/index.vue
0 → 100644
1 | +<template> | ||
2 | + <div class="login-container"> | ||
3 | + <el-form | ||
4 | + ref="loginForm" | ||
5 | + :model="loginForm" | ||
6 | + :rules="loginRules" | ||
7 | + class="login-form" | ||
8 | + auto-complete="on" | ||
9 | + label-position="left" | ||
10 | + > | ||
11 | + <!-- <img | ||
12 | + src="../../assets/images/logo.png" | ||
13 | + style=" | ||
14 | + width: 120px; | ||
15 | + height: 120px; | ||
16 | + position: absolute; | ||
17 | + top: -250px; | ||
18 | + left: 190px; | ||
19 | + " | ||
20 | + alt | ||
21 | + /> --> | ||
22 | + <img | ||
23 | + src="../../assets/images/chiken.png" | ||
24 | + style="width: 428px; height: 142px; position: absolute; top: -142px" | ||
25 | + alt | ||
26 | + /> | ||
27 | + <div class="title-container"> | ||
28 | + <h3 class="title">欢迎使用教育云平台!</h3> | ||
29 | + </div> | ||
30 | + | ||
31 | + <el-form-item prop="username"> | ||
32 | + <i class="fa fa-user" aria-hidden="true"></i> | ||
33 | + <el-input | ||
34 | + ref="username" | ||
35 | + v-model="loginForm.username" | ||
36 | + placeholder="请输入用户名" | ||
37 | + name="username" | ||
38 | + type="text" | ||
39 | + autofocus="autofocus" | ||
40 | + tabindex="1" | ||
41 | + maxlength="40" | ||
42 | + auto-complete="on" | ||
43 | + /> | ||
44 | + </el-form-item> | ||
45 | + | ||
46 | + <el-form-item prop="password"> | ||
47 | + <i class="fa fa-unlock-alt" aria-hidden="true"></i> | ||
48 | + <el-input | ||
49 | + :key="passwordType" | ||
50 | + ref="password" | ||
51 | + v-model="loginForm.password" | ||
52 | + :type="passwordType" | ||
53 | + placeholder="请输入登录密码" | ||
54 | + name="password" | ||
55 | + class="mima" | ||
56 | + maxlength="16" | ||
57 | + tabindex="2" | ||
58 | + auto-complete="on" | ||
59 | + @keyup.enter.native="submitForm" | ||
60 | + /> | ||
61 | + <span class="show-pwd" @click="showPwd"> | ||
62 | + <i | ||
63 | + class="fa" | ||
64 | + aria-hidden="true" | ||
65 | + :class="passwordType === 'password' ? 'fa-eye-slash' : 'fa-eye'" | ||
66 | + ></i> | ||
67 | + </span> | ||
68 | + </el-form-item> | ||
69 | + <el-button | ||
70 | + type="primary" | ||
71 | + style=" | ||
72 | + width: 80%; | ||
73 | + display: block; | ||
74 | + margin: 0 auto; | ||
75 | + margin-bottom: 30px; | ||
76 | + margin-top: 10px; | ||
77 | + " | ||
78 | + round | ||
79 | + :disabled="!disableClick" | ||
80 | + @click.native.prevent="submitForm" | ||
81 | + >登录</el-button | ||
82 | + > | ||
83 | + </el-form> | ||
84 | + </div> | ||
85 | +</template> | ||
86 | +<script> | ||
87 | +export default { | ||
88 | + data() { | ||
89 | + return { | ||
90 | + disableClick: true, | ||
91 | + passwordType: "password", | ||
92 | + loginForm: { | ||
93 | + username: "admin", | ||
94 | + password: "123456", | ||
95 | + }, | ||
96 | + loginRules: { | ||
97 | + username: [ | ||
98 | + { required: true, message: "请输入用户账号",trigger: "blur" } | ||
99 | + ], | ||
100 | + password: [ | ||
101 | + { required: true, message: "请输入账号密码",trigger: "blur" } | ||
102 | + ] | ||
103 | + }, | ||
104 | + }; | ||
105 | + }, | ||
106 | + methods: { | ||
107 | + showPwd() { | ||
108 | + if (this.passwordType === "password") { | ||
109 | + this.passwordType = ""; | ||
110 | + } else { | ||
111 | + this.passwordType = "password"; | ||
112 | + } | ||
113 | + this.$nextTick(() => { | ||
114 | + this.$refs.password.focus(); | ||
115 | + }); | ||
116 | + }, | ||
117 | + submitForm() { | ||
118 | + let that = this; | ||
119 | + if (this.loginForm.username === "" || this.loginForm.password === "") { | ||
120 | + this.$message({ | ||
121 | + showClose: true, | ||
122 | + message: "账号或密码不能为空", | ||
123 | + type: "error", | ||
124 | + }); | ||
125 | + return false; | ||
126 | + } else { | ||
127 | + // 真实请求参考 | ||
128 | + // this.$request.fetchLogin({ | ||
129 | + // username: that.loginForm.username, | ||
130 | + // password: that.loginForm.password | ||
131 | + // }).then(res => { | ||
132 | + // that.$restBack(res.data, () => { | ||
133 | + // that.$store.dispatch("setToken", res.data.data.access_token).then(res => { | ||
134 | + // that.$router.push({path: "/"}) | ||
135 | + // }) | ||
136 | + // }, "登录成功") | ||
137 | + // }).catch((err) => { | ||
138 | + // console.log(err) | ||
139 | + // }) | ||
140 | + | ||
141 | + // 将 username 设置为 token 存储在 store,仅为测试效果,实际存储 token 以后台返回为准 | ||
142 | + that.$store | ||
143 | + .dispatch("setToken", that.loginForm.username) | ||
144 | + .then(() => { | ||
145 | + that.$router.push({ path: "/" }); | ||
146 | + }) | ||
147 | + .catch((res) => { | ||
148 | + that.$message({ | ||
149 | + showClose: true, | ||
150 | + message: res, | ||
151 | + type: "error", | ||
152 | + }); | ||
153 | + }); | ||
154 | + } | ||
155 | + }, | ||
156 | + }, | ||
157 | + mounted() {}, | ||
158 | +}; | ||
159 | +</script> | ||
160 | +<style lang="scss"> | ||
161 | +$bg: #283443; | ||
162 | +$dark_gray: #889aa4; | ||
163 | +$light_gray: #000; | ||
164 | +$cursor: #000; | ||
165 | + | ||
166 | +@supports (-webkit-mask: none) and (not (cater-color: $cursor)) { | ||
167 | + .login-container .el-input input { | ||
168 | + color: $cursor; | ||
169 | + } | ||
170 | +} | ||
171 | +.login-container { | ||
172 | + width: 100%; | ||
173 | + height: 100vh; | ||
174 | + background: url("../../assets/images/login-bg.png") no-repeat; | ||
175 | + background-size: cover; | ||
176 | + overflow: hidden; | ||
177 | + display: flex; | ||
178 | + justify-content: center; | ||
179 | + align-items: center; | ||
180 | + .el-input { | ||
181 | + display: inline-block; | ||
182 | + height: 47px; | ||
183 | + width: 85%; | ||
184 | + input::-ms-reveal { | ||
185 | + display: none; | ||
186 | + } | ||
187 | + input { | ||
188 | + background: transparent; | ||
189 | + border: 0px; | ||
190 | + -webkit-appearance: none; | ||
191 | + border-radius: 0px; | ||
192 | + font-size:16px; | ||
193 | + color: $light_gray; | ||
194 | + height: 52px; | ||
195 | + caret-color: $cursor; | ||
196 | + | ||
197 | + &:-webkit-autofill { | ||
198 | + box-shadow: 0 0 0px 1000px #e5e5e5 inset !important; | ||
199 | + -webkit-text-fill-color: $cursor !important; | ||
200 | + } | ||
201 | + } | ||
202 | + } | ||
203 | + | ||
204 | + .el-form-item { | ||
205 | + border: 1px solid #e5e5e5; | ||
206 | + background: rgba(0, 0, 0, 0.1); | ||
207 | + border-radius: 5px; | ||
208 | + color: #454545; | ||
209 | + } | ||
210 | + .login-form { | ||
211 | + position: relative; | ||
212 | + width: 500px; | ||
213 | + height: 331px; | ||
214 | + max-width: 100%; | ||
215 | + padding: 30px 35px 0; | ||
216 | + border-radius: 10px; | ||
217 | + background: #fff; | ||
218 | + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); | ||
219 | + margin-top: 200px; | ||
220 | + box-sizing: border-box; | ||
221 | + } | ||
222 | + | ||
223 | + .tips { | ||
224 | + font-size: 14px; | ||
225 | + color: #fff; | ||
226 | + margin-bottom: 10px; | ||
227 | + | ||
228 | + span { | ||
229 | + &:first-of-type { | ||
230 | + margin-right: 16px; | ||
231 | + } | ||
232 | + } | ||
233 | + } | ||
234 | + | ||
235 | + .fa { | ||
236 | + padding: 5px 0px 6px 15px; | ||
237 | + color: $dark_gray; | ||
238 | + font-size: 20px; | ||
239 | + } | ||
240 | + | ||
241 | + .title-container { | ||
242 | + position: relative; | ||
243 | + | ||
244 | + .title { | ||
245 | + font-size: 24px; | ||
246 | + color: $light_gray; | ||
247 | + margin: 0px auto 40px auto; | ||
248 | + text-align: center; | ||
249 | + font-weight: bold; | ||
250 | + } | ||
251 | + } | ||
252 | + | ||
253 | + .show-pwd { | ||
254 | + position: absolute; | ||
255 | + right: 10px; | ||
256 | + top: 7px; | ||
257 | + font-size: 16px; | ||
258 | + color: $dark_gray; | ||
259 | + cursor: pointer; | ||
260 | + user-select: none; | ||
261 | + } | ||
262 | +} | ||
263 | +</style> | ||
264 | + |
src/views/page404.vue
0 → 100644
1 | +<template> | ||
2 | + <div class="page404"> | ||
3 | + <div class="i404"> | ||
4 | + <img src="../assets/img404/i404.png"/> | ||
5 | + <p>您的访问页面可能被删除或者不存在</p> | ||
6 | + <a href="/">返回首页</a> | ||
7 | + </div> | ||
8 | + <div class="sign"> | ||
9 | + <img src="../assets/img404/sign.png" /> | ||
10 | + </div> | ||
11 | + </div> | ||
12 | +</template> | ||
13 | + | ||
14 | +<script> | ||
15 | +export default { | ||
16 | + name: "page404", | ||
17 | + mounted () { | ||
18 | + } | ||
19 | +} | ||
20 | +</script> | ||
21 | + | ||
22 | +<style lang="scss"> | ||
23 | + .page404{ | ||
24 | + width: 100%; | ||
25 | + height: 100%; | ||
26 | + background: url("../assets/img404/bg404.jpg") no-repeat; | ||
27 | + background-size: cover; | ||
28 | + overflow: hidden; | ||
29 | + & >div{ | ||
30 | + width: 50%; | ||
31 | + height: 100%; | ||
32 | + } | ||
33 | + .i404{ | ||
34 | + float: left; | ||
35 | + display: flex; | ||
36 | + flex-direction: column; | ||
37 | + justify-content: center; | ||
38 | + align-items: center; | ||
39 | + img{ | ||
40 | + width: 500px; | ||
41 | + height: 200px; | ||
42 | + margin-top: -100px; | ||
43 | + } | ||
44 | + p{ | ||
45 | + font-size: 20px; | ||
46 | + color: #3d95ff; | ||
47 | + margin-top: 2px; | ||
48 | + } | ||
49 | + a{ | ||
50 | + display: block; | ||
51 | + width: 150px; | ||
52 | + height: 50px; | ||
53 | + color: #ffffff; | ||
54 | + background: #56a9ff; | ||
55 | + margin-top: 35px; | ||
56 | + line-height: 50px; | ||
57 | + text-align: center; | ||
58 | + border-radius: 50px; | ||
59 | + font-size: 18px; | ||
60 | + } | ||
61 | + } | ||
62 | + .sign{ | ||
63 | + float: right; | ||
64 | + img{ | ||
65 | + width: 600px; | ||
66 | + margin-top: 50px; | ||
67 | + margin-left: 50px; | ||
68 | + } | ||
69 | + } | ||
70 | + } | ||
71 | + | ||
72 | +</style> |
src/views/systemManage/roleManage.vue
0 → 100644
1 | +<template> | ||
2 | + <div class="cardshadow roleListTable"> | ||
3 | + <div> | ||
4 | + <el-button type="primary" icon="el-icon-circle-plus-outline" size="mini" @click="addRole" plain v-role-btn="'btn_100002'">新增</el-button> | ||
5 | + </div> | ||
6 | + <el-table | ||
7 | + :data="tableData" | ||
8 | + style="width: 100%"> | ||
9 | + <el-table-column | ||
10 | + type="index"> | ||
11 | + </el-table-column> | ||
12 | + <el-table-column | ||
13 | + property="name" | ||
14 | + label="角色名"> | ||
15 | + </el-table-column> | ||
16 | + <el-table-column | ||
17 | + property="describe" | ||
18 | + label="角色描述"> | ||
19 | + </el-table-column> | ||
20 | + <el-table-column | ||
21 | + prop="status" | ||
22 | + label="状态" | ||
23 | + filter-placement="bottom-end"> | ||
24 | + <template slot-scope="scope"> | ||
25 | + <el-tag | ||
26 | + :type="scope.row.status === '启用' ? 'primary' : 'danger'" | ||
27 | + disable-transitions>{{scope.row.status}} | ||
28 | + </el-tag> | ||
29 | + </template> | ||
30 | + </el-table-column> | ||
31 | + <el-table-column label="操作"> | ||
32 | + <template slot-scope="scope"> | ||
33 | + <el-button | ||
34 | + size="mini" | ||
35 | + :disabled="scope.row.name=='超级管理员'" | ||
36 | + @click="handleEdit(scope.$index, scope.row)">编辑 | ||
37 | + </el-button> | ||
38 | + <el-button | ||
39 | + size="mini" | ||
40 | + :disabled="scope.row.name=='超级管理员'" | ||
41 | + @click="roleEdit(scope.$index, scope.row)">权限分配 | ||
42 | + </el-button> | ||
43 | + <el-button | ||
44 | + size="mini" | ||
45 | + type="danger" | ||
46 | + :disabled="scope.row.name=='超级管理员'" | ||
47 | + @click="handleDelete(scope.$index, scope.row)">删除 | ||
48 | + </el-button> | ||
49 | + </template> | ||
50 | + </el-table-column> | ||
51 | + </el-table> | ||
52 | + <el-dialog title="角色信息" width="700px" class="dialog1" :visible.sync="dialogFormVisible"> | ||
53 | + <el-form :model="form"> | ||
54 | + <el-form-item label="角色名称" :label-width="formLabelWidth"> | ||
55 | + <el-input v-model="form.name" | ||
56 | + maxlength="8" | ||
57 | + show-word-limit | ||
58 | + autocomplete="off"></el-input> | ||
59 | + </el-form-item> | ||
60 | + <el-form-item label="角色描述" :label-width="formLabelWidth"> | ||
61 | + <el-input v-model="form.describe" | ||
62 | + maxlength="15" | ||
63 | + show-word-limit | ||
64 | + autocomplete="off"></el-input> | ||
65 | + </el-form-item> | ||
66 | + <el-form-item label="是否开启" :label-width="formLabelWidth"> | ||
67 | + <el-switch v-model="form.status"></el-switch> | ||
68 | + </el-form-item> | ||
69 | + </el-form> | ||
70 | + <div slot="footer" class="dialog-footer"> | ||
71 | + <el-button @click="dialogFormVisible=false">取 消</el-button> | ||
72 | + <el-button type="primary" @click="addRoleSubmit">确 定</el-button> | ||
73 | + </div> | ||
74 | + </el-dialog> | ||
75 | + <el-dialog title="权限分配" class="dialog2" @opened="setRoleData" :visible.sync="dialogFormVisible2"> | ||
76 | + <el-input | ||
77 | + placeholder="输入关键字进行过滤" | ||
78 | + v-model="filterText" | ||
79 | + style="margin-bottom: 20px" | ||
80 | + > | ||
81 | + </el-input> | ||
82 | + <el-tree | ||
83 | + :data="roleTree" | ||
84 | + node-key="r_id" | ||
85 | + show-checkbox | ||
86 | + check-on-click-node | ||
87 | + default-expand-all | ||
88 | + check-strictly | ||
89 | + :expand-on-click-node="false" | ||
90 | + ref="permission" | ||
91 | + :filter-node-method="filterNode" | ||
92 | + :props="defaultProps"> | ||
93 | + </el-tree> | ||
94 | + <div slot="footer" class="dialog-footer"> | ||
95 | + <el-button @click="dialogFormVisible2 = false">取 消</el-button> | ||
96 | + <el-button type="primary" @click="rolePermissionSubmit">确 定</el-button> | ||
97 | + </div> | ||
98 | + </el-dialog> | ||
99 | + </div> | ||
100 | +</template> | ||
101 | + | ||
102 | +<script> | ||
103 | +export default { | ||
104 | + name: "roleManage", | ||
105 | + data () { | ||
106 | + return { | ||
107 | + tableData: [], | ||
108 | + dialogFormVisible: false, | ||
109 | + dialogFormVisible2: false, | ||
110 | + form: { | ||
111 | + name: "", | ||
112 | + describe: "", | ||
113 | + status: true, | ||
114 | + permission: [] | ||
115 | + }, | ||
116 | + formLabelWidth: "120px", | ||
117 | + defaultProps: { | ||
118 | + children: "children", | ||
119 | + label: "r_name", | ||
120 | + id: "r_id" | ||
121 | + }, | ||
122 | + selectRoleId: "", | ||
123 | + selectData: [], | ||
124 | + filterText: "" | ||
125 | + } | ||
126 | + }, | ||
127 | + methods: { | ||
128 | + handleEdit (index, row) { | ||
129 | + for (let item in row) { | ||
130 | + this.form[item] = row[item] | ||
131 | + } | ||
132 | + this.form.status = row.status === "启用" | ||
133 | + this.dialogFormVisible = true | ||
134 | + }, | ||
135 | + addRole () { | ||
136 | + this.form = { | ||
137 | + name: "", | ||
138 | + describe: "", | ||
139 | + status: true | ||
140 | + } | ||
141 | + this.dialogFormVisible = true | ||
142 | + }, | ||
143 | + addRoleSubmit () { | ||
144 | + let that = this | ||
145 | + if (!this.form.name) { | ||
146 | + that.$message({ | ||
147 | + showClose: true, | ||
148 | + message: "角色名称不能为空", | ||
149 | + type: "error" | ||
150 | + }) | ||
151 | + return false | ||
152 | + } | ||
153 | + this.$request.fetchAddRole(this.form).then((res) => { | ||
154 | + that.$message({ | ||
155 | + showClose: true, | ||
156 | + message: res.data.message, | ||
157 | + type: "success" | ||
158 | + }) | ||
159 | + this.dialogFormVisible = false | ||
160 | + this.getList() | ||
161 | + }).catch((err) => { | ||
162 | + console.log(err) | ||
163 | + }) | ||
164 | + }, | ||
165 | + rolePermissionSubmit () { | ||
166 | + let that = this | ||
167 | + let rolePermissionData = { | ||
168 | + selectPermission: that.$refs.permission.getCheckedKeys(), | ||
169 | + rid: that.selectRoleId | ||
170 | + } | ||
171 | + this.$request.fetchRolePermissions(rolePermissionData).then(res => { | ||
172 | + that.$restBack(res.data, () => { | ||
173 | + that.dialogFormVisible2 = false | ||
174 | + that.getList() | ||
175 | + }) | ||
176 | + }).catch((err) => { | ||
177 | + console.log(err) | ||
178 | + }) | ||
179 | + }, | ||
180 | + roleEdit (index, row) { | ||
181 | + console.log(index, row) | ||
182 | + this.selectRoleId = row.id | ||
183 | + this.selectData = row.permission ? row.permission.split(",") : [] | ||
184 | + this.dialogFormVisible2 = true | ||
185 | + }, | ||
186 | + setRoleData () { | ||
187 | + this.$request.fetchSearchRolePermissions({rid: this.selectRoleId}).then(res => { | ||
188 | + this.$refs.permission.setCheckedKeys([]) | ||
189 | + let permissionData = res.data.data.permissionPage + "," + res.data.data.permissionButton | ||
190 | + this.$refs.permission.setCheckedKeys(permissionData.split(",")) | ||
191 | + }) | ||
192 | + }, | ||
193 | + handleDelete (index, row) { | ||
194 | + let that = this | ||
195 | + this.$request.fetchDelRole({ | ||
196 | + id: row.id | ||
197 | + }) | ||
198 | + .then(response => { | ||
199 | + console.log(response) | ||
200 | + that.$message({ | ||
201 | + showClose: true, | ||
202 | + message: response.data.message, | ||
203 | + type: "success" | ||
204 | + }) | ||
205 | + that.getList() | ||
206 | + }) | ||
207 | + .catch(err => { | ||
208 | + console.log(err) | ||
209 | + }) | ||
210 | + }, | ||
211 | + getList () { | ||
212 | + let that = this | ||
213 | + this.$request.fetchGetRoleList() | ||
214 | + .then(function (response) { | ||
215 | + console.log(response) | ||
216 | + for (let i = 0; i < response.data.rows.length; i++) { | ||
217 | + if (response.data.rows[i].status) { | ||
218 | + response.data.rows[i].status = "启用" | ||
219 | + } else { | ||
220 | + response.data.rows[i].status = "禁用" | ||
221 | + } | ||
222 | + } | ||
223 | + that.tableData = response.data.rows | ||
224 | + }) | ||
225 | + .catch(function (error) { | ||
226 | + console.log(error) | ||
227 | + }) | ||
228 | + }, | ||
229 | + filterNode (value, data) { | ||
230 | + if (!value) return true | ||
231 | + return data.r_name.indexOf(value) !== -1 | ||
232 | + } | ||
233 | + }, | ||
234 | + watch: { | ||
235 | + filterText (val) { | ||
236 | + this.$refs.permission.filter(val) | ||
237 | + } | ||
238 | + }, | ||
239 | + computed: { | ||
240 | + roleTree: function () { | ||
241 | + let roleData = this.$store.getters.roleData | ||
242 | + for (let i = 0; i < roleData.length; i++) { | ||
243 | + if (roleData[i].redirect === "/404") { | ||
244 | + roleData.splice(i, 1) | ||
245 | + } | ||
246 | + } | ||
247 | + return roleData | ||
248 | + } | ||
249 | + }, | ||
250 | + mounted () { | ||
251 | + this.getList() | ||
252 | + } | ||
253 | +} | ||
254 | +</script> | ||
255 | + | ||
256 | +<style scoped> | ||
257 | + .nameinput { | ||
258 | + width: 150px; | ||
259 | + } | ||
260 | + | ||
261 | + .phoneinput { | ||
262 | + width: 120px; | ||
263 | + } | ||
264 | + | ||
265 | + .datepicker { | ||
266 | + width: 260px; | ||
267 | + } | ||
268 | + .dialog1 .el-dialog { | ||
269 | + width: 35%; | ||
270 | + } | ||
271 | + | ||
272 | + .dialog1 .el-dialog .el-form { | ||
273 | + width: 500px; | ||
274 | + margin: 0 auto; | ||
275 | + } | ||
276 | + | ||
277 | + .el-form-item__content { | ||
278 | + margin-left: 120px; | ||
279 | + width: 300px; | ||
280 | + } | ||
281 | + | ||
282 | +</style> | ||
283 | + |