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 | 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 | + | ... | ... |