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