pull/24/head
1234567 2 months ago
parent 65e2715746
commit 9b2c9292a3

@ -1,5 +1,7 @@
import Vue from 'vue' import Vue from 'vue'
import Vuex from 'vuex' import Vuex from 'vuex'
// 引入各个模块的 Vuex 状态管理文件
import common from './modules/common' import common from './modules/common'
import user from './modules/user' import user from './modules/user'
import article from './modules/article' import article from './modules/article'
@ -7,18 +9,26 @@ import message from './modules/message'
import wxUserTags from './modules/wxUserTags' import wxUserTags from './modules/wxUserTags'
import wxAccount from './modules/wxAccount' import wxAccount from './modules/wxAccount'
// 注册 Vuex 插件,使其可用于 Vue 中
Vue.use(Vuex) Vue.use(Vuex)
export default new Vuex.Store({ export default new Vuex.Store({
modules: { // 使用 modules 来组织不同的子模块
common, modules: {
user, // 引入并注册各个模块
article, common, // 公共模块,可能用于存储一些通用的状态
message, user, // 用户模块,存储用户信息相关的状态
wxUserTags, article, // 文章模块,存储与文章相关的状态
wxAccount message, // 消息模块,存储消息相关的状态
}, wxUserTags, // 微信用户标签模块,管理微信用户标签的状态
mutations: { wxAccount // 微信账号模块,管理微信账号相关的状态
}, },
strict: true
// mutations 用于同步修改状态,这里没有定义任何 mutations可根据需求进行扩展
mutations: {
// 这里可以添加全局的 mutation但目前没有定义
},
// 启用严格模式,开发环境下会对状态的修改进行检查,确保只能通过 mutation 修改状态
strict: true
}) })

@ -1,32 +1,59 @@
import Vue from 'vue' import Vue from 'vue';
export default { export default {
namespaced: true, // Vuex模块启用命名空间
state: { namespaced: true,
ACCOUNT_TYPES:{
1:'订阅号', // Vuex的state用来存储应用状态
2:'服务号' state: {
}, // 账户类型映射数字ID到账户类型名称
accountList:[], ACCOUNT_TYPES: {
selectedAppid:'' 1: '订阅号',
}, 2: '服务号'
mutations: { },
updateAccountList (state, list) {
state.accountList = list // 存储账户列表
if(!list.length)return accountList: [],
if(!state.selectedAppid){
let appidCookie = Vue.cookie.get('appid') // 当前选中的Appid用来标识选择的账号
let selectedAppid = appidCookie?appidCookie:list[0].appid selectedAppid: ''
this.commit('wxAccount/selectAccount',selectedAppid) },
}
}, // Vuex的mutations用来修改state
selectAccount (state, appid) { mutations: {
Vue.cookie.set('appid',appid) // 更新账户列表
let oldAppid = state.selectedAppid updateAccountList (state, list) {
state.selectedAppid = appid // 更新state中的accountList
if(oldAppid){//切换账号时刷新网页 state.accountList = list;
location.reload();
} // 如果列表为空,直接返回
}, if (!list.length) return;
}
} // 如果当前没有选中的Appid则从cookie或列表中选择一个默认Appid
if (!state.selectedAppid) {
let appidCookie = Vue.cookie.get('appid');
// 获取cookie中的appid如果有则使用cookie中的appid否则使用列表中的第一个Appid
let selectedAppid = appidCookie ? appidCookie : list[0].appid;
// 通过commit调用mutation更新选中的账号
this.commit('wxAccount/selectAccount', selectedAppid);
}
},
// 选择某个账号切换Appid
selectAccount (state, appid) {
// 更新cookie中的appid保存选中的Appid
Vue.cookie.set('appid', appid);
// 记录上一个选中的Appid
let oldAppid = state.selectedAppid;
// 更新当前选中的Appid
state.selectedAppid = appid;
// 如果选中的Appid发生变化则刷新页面
if (oldAppid) {
location.reload();
}
}
}
};

@ -1,12 +1,20 @@
export default { export default {
namespaced: true, // 启用 Vuex 模块的命名空间,避免命名冲突
state: { namespaced: true,
tags:[]
}, // state 存储模块的状态
mutations: { state: {
updateTags (state, tags) { // tags 用来存储标签数据的数组
state.tags = tags tags: []
} },
}
// mutations 用来修改 state 中的状态
mutations: {
// 更新 tags 数组的内容
updateTags (state, tags) {
// 将传入的 tags 更新到 state 中
state.tags = tags;
} }
}
};

@ -4,74 +4,81 @@ import router from '@/router'
import qs from 'qs' import qs from 'qs'
import merge from 'lodash/merge' import merge from 'lodash/merge'
import { clearLoginInfo } from '@/utils' import { clearLoginInfo } from '@/utils'
const baseUrl = '/wx'
const baseUrl = '/wx' // 设置请求的基础路径
// 创建axios实例
const http = axios.create({ const http = axios.create({
timeout: 1000 * 30, timeout: 1000 * 30, // 设置请求超时为30秒
withCredentials: true, withCredentials: true, // 允许携带跨域请求的cookie
headers: { headers: {
'Content-Type': 'application/json; charset=utf-8' 'Content-Type': 'application/json; charset=utf-8' // 默认请求头为json格式
} }
}) })
/** /**
* 请求拦截 * 请求拦截器
*/ * 在每个请求发送之前加入token从cookie中获取
*/
http.interceptors.request.use(config => { http.interceptors.request.use(config => {
config.headers['token'] = Vue.cookie.get('token') // 请求头带上token config.headers['token'] = Vue.cookie.get('token') // 在请求头中加入token
return config return config // 返回请求配置
}, error => { }, error => {
return Promise.reject(error) return Promise.reject(error) // 请求出错时返回Promise拒绝
}) })
/** /**
* 响应拦截 * 响应拦截器
*/ * 对响应数据进行拦截处理
* 如果返回的状态码为401未授权则清除登录信息并跳转到登录页
*/
http.interceptors.response.use(response => { http.interceptors.response.use(response => {
if (response.data && response.data.code === 401) { // 401, token失效 if (response.data && response.data.code === 401) { // 判断返回的code是否为401代表token失效
clearLoginInfo() clearLoginInfo() // 清除登录信息
router.push({ name: 'login' }) router.push({ name: 'login' }) // 跳转到登录页面
} }
return response return response // 返回响应数据
}, error => { }, error => {
return Promise.reject(error) return Promise.reject(error) // 响应出错时返回Promise拒绝
}) })
/** /**
* 请求地址处理 * 请求地址处理函数
* @param {*} actionName action方法名称 * @param {*} actionName 接口的名称拼接成完整的URL
*/ * @returns {string} 拼接后的完整URL
*/
http.adornUrl = (actionName) => { http.adornUrl = (actionName) => {
// 非生产环境 && 开启代理, 接口前缀统一使用[/proxyApi/]前缀做代理拦截! // 在开发环境下,如果开启了代理,则请求路径会带上代理前缀
return baseUrl + actionName return baseUrl + actionName // 返回完整的请求URL
} }
/** /**
* get请求参数处理 * get请求的参数处理
* @param {*} params 参数对象 * @param {*} params 请求的参数对象
* @param {*} openDefultParams 是否开启默认参数? * @param {*} openDefultParams 是否开启默认参数
*/ * @returns {object} 处理后的参数对象
*/
http.adornParams = (params = {}, openDefultParams = true) => { http.adornParams = (params = {}, openDefultParams = true) => {
var defaults = { const defaults = {
't': new Date().getTime() 't': new Date().getTime() // 添加时间戳参数,防止缓存
} }
return openDefultParams ? merge(defaults, params) : params return openDefultParams ? merge(defaults, params) : params // 合并默认参数和传入的参数
} }
/** /**
* post请求数据处理 * post请求的数据处理
* @param {*} data 数据对象 * @param {*} data 请求的数据对象
* @param {*} openDefultdata 是否开启默认数据? * @param {*} openDefultdata 是否开启默认数据
* @param {*} contentType 数据格式 * @param {*} contentType 数据格式类型'json''form'
* json: 'application/json; charset=utf-8' * @returns {string} 处理后的数据
* form: 'application/x-www-form-urlencoded; charset=utf-8' */
*/
http.adornData = (data = {}, openDefultdata = true, contentType = 'json') => { http.adornData = (data = {}, openDefultdata = true, contentType = 'json') => {
var defaults = { const defaults = {
't': new Date().getTime() 't': new Date().getTime() // 添加时间戳参数,防止缓存
} }
data = openDefultdata ? merge(defaults, data) : data data = openDefultdata ? merge(defaults, data) : data // 合并默认数据和传入的数据
return contentType === 'json' ? JSON.stringify(data) : qs.stringify(data) // 根据不同的contentType处理数据格式
return contentType === 'json' ? JSON.stringify(data) : qs.stringify(data)
} }
export default http export default http // 导出axios实例供其他模块使用

@ -3,56 +3,76 @@ import router from '@/router'
import store from '@/store' import store from '@/store'
/** /**
* 获取uuid * 获取UUID
*/ * 生成一个标准的UUID例如xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
* 使用随机数和指定格式的规则生成UUID
*/
export function getUUID() { export function getUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
return (c === 'x' ? (Math.random() * 16 | 0) : ('r&0x3' | '0x8')).toString(16) return (c === 'x' ? (Math.random() * 16 | 0) : ('r&0x3' | '0x8')).toString(16)
}) })
} }
/** /**
* 是否有权限 * 检查是否有某个权限
* @param {*} key * @param {*} key 权限的标识符
*/ * @returns {boolean} 如果权限列表中包含该权限返回true否则返回false
*/
export function isAuth(key) { export function isAuth(key) {
return JSON.parse(sessionStorage.getItem('permissions') || '[]').indexOf(key) !== -1 || false // 从 sessionStorage 中获取权限列表,并转换为数组,如果没有权限列表,默认返回空数组
return JSON.parse(sessionStorage.getItem('permissions') || '[]').indexOf(key) !== -1 || false
} }
/** /**
* 树形数据转换 * 将平面数据转换为树形数据
* @param {*} data * @param {*} data 原始平面数据
* @param {*} id * @param {*} id 唯一标识符字段默认为'id'
* @param {*} pid * @param {*} pid 父级标识符字段默认为'parentId'
*/ * @returns {Array} 转换后的树形数据
*/
export function treeDataTranslate(data, id = 'id', pid = 'parentId') { export function treeDataTranslate(data, id = 'id', pid = 'parentId') {
var res = [] var res = [] // 存储最终的树形结构
var temp = {} var temp = {} // 临时存储每个节点,以便快速查找父节点
for (var i = 0; i < data.length; i++) {
temp[data[i][id]] = data[i] // 将数据转换为临时对象key为节点的id值为节点本身
} for (var i = 0; i < data.length; i++) {
for (var k = 0; k < data.length; k++) { temp[data[i][id]] = data[i]
if (temp[data[k][pid]] && data[k][id] !== data[k][pid]) { }
if (!temp[data[k][pid]]['children']) {
temp[data[k][pid]]['children'] = [] // 遍历数据根据pid将节点组织成树形结构
} for (var k = 0; k < data.length; k++) {
if (!temp[data[k][pid]]['_level']) { // 如果节点的父节点存在并且当前节点的id不等于父节点的id
temp[data[k][pid]]['_level'] = 1 if (temp[data[k][pid]] && data[k][id] !== data[k][pid]) {
} // 如果父节点没有'children'属性,则初始化为数组
data[k]['_level'] = temp[data[k][pid]]._level + 1 if (!temp[data[k][pid]]['children']) {
temp[data[k][pid]]['children'].push(data[k]) temp[data[k][pid]]['children'] = []
} else { }
res.push(data[k]) // 如果父节点没有'_level'属性则设置为1
} if (!temp[data[k][pid]]['_level']) {
} temp[data[k][pid]]['_level'] = 1
return res }
// 当前节点的级别为父节点的级别+1
data[k]['_level'] = temp[data[k][pid]]._level + 1
// 将当前节点推送到父节点的children数组中
temp[data[k][pid]]['children'].push(data[k])
} else {
// 如果当前节点是根节点,直接推送到结果数组中
res.push(data[k])
}
}
return res // 返回转换后的树形数据
} }
/** /**
* 清除登录信息 * 清除登录信息
*/ * 用于用户退出时清理本地存储的登录信息
*/
export function clearLoginInfo() { export function clearLoginInfo() {
Vue.cookie.delete('token') // 删除cookie中的'token'
//store.commit('resetStore') Vue.cookie.delete('token')
router.options.isAddDynamicMenuRoutes = false // 目前注释掉了重置store的操作若需要可以解除注释
// store.commit('resetStore')
// 重置动态菜单路由标志
router.options.isAddDynamicMenuRoutes = false
} }

@ -1,31 +1,36 @@
/** /**
* 邮箱 * 验证邮箱格式
* @param {*} s * @param {*} s - 需要验证的邮箱地址
*/ * @returns {boolean} - 返回是否是有效的邮箱地址
*/
export function isEmail(s) { export function isEmail(s) {
return /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((.[a-zA-Z0-9_-]{2,3}){1,2})$/.test(s) return /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\.[a-zA-Z0-9_-]{2,3}){1,2})$/.test(s)
} }
/** /**
* 手机号码 * 验证手机号码格式中国手机号
* @param {*} s * @param {*} s - 需要验证的手机号
*/ * @returns {boolean} - 返回是否是有效的手机号码
export function isMobile(s) { */
export function isMobile(s) {
return /^1[0-9]{10}$/.test(s) return /^1[0-9]{10}$/.test(s)
} }
/** /**
* 电话号码 * 验证固定电话号码格式
* @param {*} s * @param {*} s - 需要验证的电话号码
*/ * @returns {boolean} - 返回是否是有效的电话号码包括区号和本地号码
export function isPhone(s) { */
export function isPhone(s) {
return /^([0-9]{3,4}-)?[0-9]{7,8}$/.test(s) return /^([0-9]{3,4}-)?[0-9]{7,8}$/.test(s)
} }
/** /**
* URL地址 * 验证URL地址格式
* @param {*} s * @param {*} s - 需要验证的URL地址
*/ * @returns {boolean} - 返回是否是有效的URL地址包括http或https协议
export function isURL(s) { */
export function isURL(s) {
return /^http[s]?:\/\/.*/.test(s) return /^http[s]?:\/\/.*/.test(s)
} }

@ -1,61 +1,81 @@
<template> <template>
<!-- 404 错误页面的模板 -->
<div class="site-wrapper site-page--not-found"> <div class="site-wrapper site-page--not-found">
<div class="site-content__wrapper"> <div class="site-content__wrapper">
<div class="site-content"> <div class="site-content">
<h2 class="not-found-title">400</h2> <!-- 错误代码 -->
<p class="not-found-desc">抱歉您访问的页面<em>失联</em> ...</p> <h2 class="not-found-title">400</h2>
<el-button @click="$router.go(-1)"></el-button> <!-- 错误描述 -->
<el-button type="primary" class="not-found-btn-gohome" @click="$router.push({ name: 'home' })">进入首页</el-button> <p class="not-found-desc">抱歉您访问的页面<em>失联</em> ...</p >
</div> <!-- 返回上一页按钮 -->
</div> <el-button @click="$router.go(-1)"></el-button>
<!-- 返回首页按钮 -->
<el-button type="primary" class="not-found-btn-gohome" @click="$router.push({ name: 'home' })">进入首页</el-button>
</div> </div>
</template> </div>
</div>
<script> </template>
export default {
} <script>
</script> export default {
// JavaScript
<style lang="scss"> }
.site-wrapper.site-page--not-found { </script>
position: absolute;
<style lang="scss">
/* 整个404页面的外部容器 */
.site-wrapper.site-page--not-found {
position: absolute; /* 定位到页面的绝对位置 */
top: 0; top: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
overflow: hidden; overflow: hidden; /* 防止内容溢出 */
/* 内容包裹层 */
.site-content__wrapper { .site-content__wrapper {
padding: 0; padding: 0;
margin: 0; margin: 0;
background-color: #fff; background-color: #fff; /* 设置背景色为白色 */
} }
/* 页面内容容器 */
.site-content { .site-content {
position: fixed; position: fixed; /* 固定位置 */
top: 15%; top: 15%; /* 距离顶部15% */
left: 50%; left: 50%; /* 距离左边50% */
z-index: 2; z-index: 2; /* 确保内容在其他元素之上 */
padding: 30px; padding: 30px;
text-align: center; text-align: center; /* 内容居中 */
transform: translate(-50%, 0); transform: translate(-50%, 0); /* 将内容水平居中 */
} }
/* 错误标题 */
.not-found-title { .not-found-title {
margin: 20px 0 15px; margin: 20px 0 15px;
font-size: 10em; font-size: 10em; /* 大字体 */
font-weight: 400; font-weight: 400;
color: rgb(55, 71, 79); color: rgb(55, 71, 79); /* 文字颜色 */
} }
/* 错误描述 */
.not-found-desc { .not-found-desc {
margin: 0 0 30px; margin: 0 0 30px;
font-size: 26px; font-size: 26px;
text-transform: uppercase; text-transform: uppercase; /* 将文本转换为大写 */
color: rgb(118, 131, 143); color: rgb(118, 131, 143); /* 文字颜色 */
> em {
font-style: normal; /* 强调标签 <em> 样式 */
color: #ee8145; > em {
} font-style: normal;
color: #ee8145; /* 设置颜色 */
} }
}
/* 返回首页按钮的左边距 */
.not-found-btn-gohome { .not-found-btn-gohome {
margin-left: 30px; margin-left: 30px;
}
} }
} </style>
</style>

@ -1,12 +1,18 @@
<template> <template>
<!-- 模块容器 div -->
<div class="mod-home"> <div class="mod-home">
<h3>欢迎使用微信管理系统</h3> <!-- 欢迎标题 -->
<h3>欢迎使用微信管理系统</h3>
</div> </div>
</template> </template>
<style>
.mod-home { <style>
/* 样式部分 */
.mod-home {
/* 设置行高,增加文本的可读性 */
line-height: 2.5; line-height: 2.5;
/* 使文本水平居中对齐 */
text-align: center; text-align: center;
} }
</style> </style>

@ -1,184 +1,220 @@
<template> <template>
<div class="site-wrapper site-page--login"> <div class="site-wrapper site-page--login">
<div class="site-content__wrapper"> <!-- 页面容器背景层 -->
<div class="site-content"> <div class="site-content__wrapper">
<div class="brand-info"> <!-- 页面内容容器 -->
<h2 class="brand-info__text">微信后台管理系统</h2> <div class="site-content">
<p class="brand-info__intro">微信公众号后台管理系统</p> <!-- 品牌信息部分 -->
</div> <div class="brand-info">
<div class="login-main"> <h2 class="brand-info__text">微信后台管理系统</h2>
<h3 class="login-title">管理员登录</h3> <p class="brand-info__intro">微信公众号后台管理系统</p >
<el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmit()" status-icon>
<el-form-item prop="userName">
<el-input v-model="dataForm.userName" placeholder="帐号"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input v-model="dataForm.password" type="password" placeholder="密码"></el-input>
</el-form-item>
<el-form-item prop="captcha">
<el-row :gutter="20">
<el-col :span="14">
<el-input v-model="dataForm.captcha" placeholder="验证码">
</el-input>
</el-col>
<el-col :span="10" class="login-captcha">
<img :src="captchaPath" @click="getCaptcha()" alt="">
</el-col>
</el-row>
</el-form-item>
<el-form-item>
<el-button class="login-btn-submit" type="primary" @click="dataFormSubmit()"></el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</div> </div>
</template>
<!-- 登录表单 -->
<div class="login-main">
<h3 class="login-title">管理员登录</h3>
<!-- 表单绑定了 model validation 规则 -->
<el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmit()" status-icon>
<!-- 用户名输入框 -->
<el-form-item prop="userName">
<el-input v-model="dataForm.userName" placeholder="帐号"></el-input>
</el-form-item>
<!-- 密码输入框 -->
<el-form-item prop="password">
<el-input v-model="dataForm.password" type="password" placeholder="密码"></el-input>
</el-form-item>
<!-- 验证码输入框 -->
<el-form-item prop="captcha">
<el-row :gutter="20">
<el-col :span="14">
<el-input v-model="dataForm.captcha" placeholder="验证码"></el-input>
</el-col>
<el-col :span="10" class="login-captcha">
<!-- 验证码图片点击刷新验证码 -->
< img :src="captchaPath" @click="getCaptcha()" alt="">
</el-col>
</el-row>
</el-form-item>
<!-- 登录按钮 -->
<el-form-item>
<el-button class="login-btn-submit" type="primary" @click="dataFormSubmit()"></el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</div>
</template>
<script> <script>
import { getUUID } from '@/utils' import { getUUID } from '@/utils' // UUID
export default { export default {
data() { data() {
return { return {
dataForm: { //
userName: '', dataForm: {
password: '', userName: '', //
uuid: '', password: '', //
captcha: '' uuid: '', // UUID
}, captcha: '' //
dataRule: { },
userName: [ //
{ required: true, message: '帐号不能为空', trigger: 'blur' } dataRule: {
], userName: [
password: [ { required: true, message: '帐号不能为空', trigger: 'blur' }
{ required: true, message: '密码不能为空', trigger: 'blur' } ],
], password: [
captcha: [ { required: true, message: '密码不能为空', trigger: 'blur' }
{ required: true, message: '验证码不能为空', trigger: 'blur' } ],
] captcha: [
}, { required: true, message: '验证码不能为空', trigger: 'blur' }
captchaPath: '' ]
} },
}, captchaPath: '' //
created() { }
this.getCaptcha() },
}, created() {
methods: { //
// this.getCaptcha()
dataFormSubmit() { },
this.$refs['dataForm'].validate((valid) => { methods: {
if (valid) { //
this.$http({ dataFormSubmit() {
url: this.$http.adornUrl('/sys/login'), //
method: 'post', this.$refs['dataForm'].validate((valid) => {
data: this.$http.adornData({ if (valid) {
'username': this.dataForm.userName, //
'password': this.dataForm.password, this.$http({
'uuid': this.dataForm.uuid, url: this.$http.adornUrl('/sys/login'), //
'captcha': this.dataForm.captcha method: 'post',
}) data: this.$http.adornData({
}).then(({ data }) => { 'username': this.dataForm.userName,
if (data && data.code === 200) { 'password': this.dataForm.password,
this.$cookie.set('token', data.token) 'uuid': this.dataForm.uuid,
this.$router.replace({ name: 'home' }) 'captcha': this.dataForm.captcha
} else { })
this.getCaptcha() }).then(({ data }) => {
this.$message.error(data.msg) if (data && data.code === 200) {
} // token
}) this.$cookie.set('token', data.token)
} this.$router.replace({ name: 'home' })
}) } else {
}, //
// this.getCaptcha()
getCaptcha() { this.$message.error(data.msg)
this.dataForm.uuid = getUUID() }
this.captchaPath = this.$http.adornUrl(`/captcha?uuid=${this.dataForm.uuid}`) })
} }
} })
},
// UUID
getCaptcha() {
this.dataForm.uuid = getUUID() // UUID
//
this.captchaPath = this.$http.adornUrl(`/captcha?uuid=${this.dataForm.uuid}`)
}
}
} }
</script> </script>
<style lang="scss"> <style lang="scss">
.site-wrapper.site-page--login { .site-wrapper.site-page--login {
position: absolute; position: absolute;
top: 0; top: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
background-color: rgba(38, 50, 56, 0.5); background-color: rgba(38, 50, 56, 0.5); /* 半透明背景 */
overflow: hidden; overflow: hidden;
&:before {
position: fixed; /* 页面背景渐变效果 */
top: 0; &:before {
left: 0; position: fixed;
z-index: -1; top: 0;
width: 100%; left: 0;
height: 100%; z-index: -1; /* 确保背景层在最底层 */
content: ""; width: 100%;
background-color: #fa8bff; height: 100%;
background-image: linear-gradient( content: "";
45deg, background-color: #fa8bff;
#fa8bff 0%, background-image: linear-gradient(
#2bd2ff 52%, 45deg,
#2bff88 90% #fa8bff 0%,
); #2bd2ff 52%,
background-size: cover; #2bff88 90%
} );
.site-content__wrapper { background-size: cover;
position: absolute; }
top: 0;
right: 0; .site-content__wrapper {
bottom: 0; position: absolute;
left: 0; top: 0;
padding: 0; right: 0;
margin: 0; bottom: 0;
overflow-x: hidden; left: 0;
overflow-y: auto; padding: 0;
background-color: transparent; margin: 0;
} overflow-x: hidden;
.site-content { overflow-y: auto;
min-height: 100%; background-color: transparent;
padding: 30px 500px 30px 30px; }
}
.brand-info { .site-content {
margin: 220px 100px 0 90px; min-height: 100%;
color: #fff; padding: 30px 500px 30px 30px;
} }
.brand-info__text {
margin: 0 0 22px 0; /* 品牌信息样式 */
font-size: 48px; .brand-info {
font-weight: 400; margin: 220px 100px 0 90px;
text-transform: uppercase; color: #fff;
} }
.brand-info__intro {
margin: 10px 0; .brand-info__text {
font-size: 16px; margin: 0 0 22px 0;
line-height: 1.58; font-size: 48px;
opacity: 0.6; font-weight: 400;
} text-transform: uppercase;
.login-main { }
position: absolute;
top: 0; .brand-info__intro {
right: 0; margin: 10px 0;
padding: 150px 60px 180px; font-size: 16px;
width: 470px; line-height: 1.58;
min-height: 100%; opacity: 0.6;
background-color: #fff; }
}
.login-title { /* 登录表单样式 */
font-size: 16px; .login-main {
} position: absolute;
.login-captcha { top: 0;
overflow: hidden; right: 0;
> img { padding: 150px 60px 180px;
width: 100%; width: 470px;
cursor: pointer; min-height: 100%;
} background-color: #fff;
} }
.login-btn-submit {
width: 100%; .login-title {
margin-top: 38px; font-size: 16px;
} }
/* 验证码图片样式 */
.login-captcha {
overflow: hidden;
> img {
width: 100%;
cursor: pointer; /* 鼠标指针变成手形,表示可以点击 */
}
}
/* 登录按钮样式 */
.login-btn-submit {
width: 100%;
margin-top: 38px;
}
} }
</style> </style>

@ -1,33 +1,53 @@
<template> <template>
<el-form> <el-form>
<h2>布局设置</h2> <!-- 布局设置表单标题 -->
<el-form-item label="导航条类型"> <h2>布局设置</h2>
<el-radio-group v-model="navbarLayoutType">
<el-radio label="default" border>default</el-radio> <!-- 导航条类型设置项 -->
<el-radio label="inverse" border>inverse</el-radio> <el-form-item label="导航条类型">
</el-radio-group> <!-- 导航条类型选择框使用 radio 按钮选择 'default' 'inverse' -->
</el-form-item> <el-radio-group v-model="navbarLayoutType">
<el-form-item label="侧边栏皮肤"> <el-radio label="default" border>default</el-radio>
<el-radio-group v-model="sidebarLayoutSkin"> <el-radio label="inverse" border>inverse</el-radio>
<el-radio label="light" border>light</el-radio> </el-radio-group>
<el-radio label="dark" border>dark</el-radio> </el-form-item>
</el-radio-group>
</el-form-item> <!-- 侧边栏皮肤设置项 -->
<el-form-item label="侧边栏皮肤">
<!-- 侧边栏皮肤选择框使用 radio 按钮选择 'light' 'dark' -->
<el-radio-group v-model="sidebarLayoutSkin">
<el-radio label="light" border>light</el-radio>
<el-radio label="dark" border>dark</el-radio>
</el-radio-group>
</el-form-item>
</el-form> </el-form>
</template> </template>
<script> <script>
export default { export default {
computed: { computed: {
navbarLayoutType: { //
get() { return this.$store.state.common.navbarLayoutType }, navbarLayoutType: {
set(val) { this.$store.commit('common/updateNavbarLayoutType', val) } // getter Vuex navbarLayoutType
}, get() {
sidebarLayoutSkin: { return this.$store.state.common.navbarLayoutType
get() { return this.$store.state.common.sidebarLayoutSkin }, },
set(val) { this.$store.commit('common/updateSidebarLayoutSkin', val) } // setter Vuex navbarLayoutType
} set(val) {
} this.$store.commit('common/updateNavbarLayoutType', val)
}
},
//
sidebarLayoutSkin: {
// getter Vuex sidebarLayoutSkin
get() {
return this.$store.state.common.sidebarLayoutSkin
},
// setter Vuex sidebarLayoutSkin
set(val) {
this.$store.commit('common/updateSidebarLayoutSkin', val)
}
}
}
} }
</script> </script>

@ -1,127 +1,150 @@
<template> <template>
<!-- Dialog弹框用于配置云存储 -->
<el-dialog title="云存储配置" :close-on-click-modal="false" :visible.sync="visible"> <el-dialog title="云存储配置" :close-on-click-modal="false" :visible.sync="visible">
<el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmit()" label-width="120px">
<el-form-item size="mini" label="存储类型"> <!-- 表单组件model 绑定 dataFormrules 绑定 dataRule -->
<el-radio-group v-model="dataForm.type"> <el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmit()" label-width="120px">
<el-radio :label="1">七牛</el-radio>
<el-radio :label="2">阿里云</el-radio> <!-- 存储类型选择项 -->
<el-radio :label="3">腾讯云</el-radio> <el-form-item size="mini" label="存储类型">
</el-radio-group> <el-radio-group v-model="dataForm.type">
</el-form-item> <el-radio :label="1">七牛</el-radio>
<template v-if="dataForm.type === 1"> <el-radio :label="2">阿里云</el-radio>
<el-form-item label="域名"> <el-radio :label="3">腾讯云</el-radio>
<el-input v-model="dataForm.qiniuDomain" placeholder="七牛绑定的域名"></el-input> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="路径前缀">
<el-input v-model="dataForm.qiniuPrefix" placeholder="不设置默认为空"></el-input> <!-- 当选择七牛云时显示七牛相关配置项 -->
</el-form-item> <template v-if="dataForm.type === 1">
<el-form-item label="AccessKey"> <el-form-item label="域名">
<el-input v-model="dataForm.qiniuAccessKey" placeholder="七牛AccessKey"></el-input> <el-input v-model="dataForm.qiniuDomain" placeholder="七牛绑定的域名"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="SecretKey"> <el-form-item label="路径前缀">
<el-input v-model="dataForm.qiniuSecretKey" placeholder="七牛SecretKey"></el-input> <el-input v-model="dataForm.qiniuPrefix" placeholder="不设置默认为空"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="空间名"> <el-form-item label="AccessKey">
<el-input v-model="dataForm.qiniuBucketName" placeholder="七牛存储空间名"></el-input> <el-input v-model="dataForm.qiniuAccessKey" placeholder="七牛AccessKey"></el-input>
</el-form-item> </el-form-item>
</template> <el-form-item label="SecretKey">
<template v-else-if="dataForm.type === 2"> <el-input v-model="dataForm.qiniuSecretKey" placeholder="七牛SecretKey"></el-input>
<el-form-item label="域名"> </el-form-item>
<el-input v-model="dataForm.aliyunDomain" placeholder="阿里云绑定的域名"></el-input> <el-form-item label="空间名">
</el-form-item> <el-input v-model="dataForm.qiniuBucketName" placeholder="七牛存储空间名"></el-input>
<el-form-item label="路径前缀"> </el-form-item>
<el-input v-model="dataForm.aliyunPrefix" placeholder="不设置默认为空"></el-input> </template>
</el-form-item>
<el-form-item label="EndPoint"> <!-- 当选择阿里云时显示阿里云相关配置项 -->
<el-input v-model="dataForm.aliyunEndPoint" placeholder="阿里云EndPoint"></el-input> <template v-else-if="dataForm.type === 2">
</el-form-item> <el-form-item label="域名">
<el-form-item label="AccessKeyId"> <el-input v-model="dataForm.aliyunDomain" placeholder="阿里云绑定的域名"></el-input>
<el-input v-model="dataForm.aliyunAccessKeyId" placeholder="阿里云AccessKeyId"></el-input> </el-form-item>
</el-form-item> <el-form-item label="路径前缀">
<el-form-item label="AccessKeySecret"> <el-input v-model="dataForm.aliyunPrefix" placeholder="不设置默认为空"></el-input>
<el-input v-model="dataForm.aliyunAccessKeySecret" placeholder="阿里云AccessKeySecret"></el-input> </el-form-item>
</el-form-item> <el-form-item label="EndPoint">
<el-form-item label="BucketName"> <el-input v-model="dataForm.aliyunEndPoint" placeholder="阿里云EndPoint"></el-input>
<el-input v-model="dataForm.aliyunBucketName" placeholder="阿里云BucketName"></el-input> </el-form-item>
</el-form-item> <el-form-item label="AccessKeyId">
</template> <el-input v-model="dataForm.aliyunAccessKeyId" placeholder="阿里云AccessKeyId"></el-input>
<template v-else-if="dataForm.type === 3"> </el-form-item>
<el-form-item label="域名"> <el-form-item label="AccessKeySecret">
<el-input v-model="dataForm.qcloudDomain" placeholder="腾讯云绑定的域名"></el-input> <el-input v-model="dataForm.aliyunAccessKeySecret" placeholder="阿里云AccessKeySecret"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="路径前缀"> <el-form-item label="BucketName">
<el-input v-model="dataForm.qcloudPrefix" placeholder="不设置默认为空"></el-input> <el-input v-model="dataForm.aliyunBucketName" placeholder="阿里云BucketName"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="AppId"> </template>
<el-input v-model="dataForm.qcloudAppId" placeholder="腾讯云AppId"></el-input>
</el-form-item> <!-- 当选择腾讯云时显示腾讯云相关配置项 -->
<el-form-item label="SecretId"> <template v-else-if="dataForm.type === 3">
<el-input v-model="dataForm.qcloudSecretId" placeholder="腾讯云SecretId"></el-input> <el-form-item label="域名">
</el-form-item> <el-input v-model="dataForm.qcloudDomain" placeholder="腾讯云绑定的域名"></el-input>
<el-form-item label="SecretKey"> </el-form-item>
<el-input v-model="dataForm.qcloudSecretKey" placeholder="腾讯云SecretKey"></el-input> <el-form-item label="路径前缀">
</el-form-item> <el-input v-model="dataForm.qcloudPrefix" placeholder="不设置默认为空"></el-input>
<el-form-item label="BucketName"> </el-form-item>
<el-input v-model="dataForm.qcloudBucketName" placeholder="腾讯云BucketName"></el-input> <el-form-item label="AppId">
</el-form-item> <el-input v-model="dataForm.qcloudAppId" placeholder="腾讯云AppId"></el-input>
<el-form-item label="Bucket所属地区"> </el-form-item>
<el-input v-model="dataForm.qcloudRegion" placeholder="如sh可选值 华南gz 华北tj 华东sh"></el-input> <el-form-item label="SecretId">
</el-form-item> <el-input v-model="dataForm.qcloudSecretId" placeholder="腾讯云SecretId"></el-input>
</template> </el-form-item>
</el-form> <el-form-item label="SecretKey">
<span slot="footer" class="dialog-footer"> <el-input v-model="dataForm.qcloudSecretKey" placeholder="腾讯云SecretKey"></el-input>
<el-button @click="visible = false">取消</el-button> </el-form-item>
<el-button type="primary" @click="dataFormSubmit()"></el-button> <el-form-item label="BucketName">
</span> <el-input v-model="dataForm.qcloudBucketName" placeholder="腾讯云BucketName"></el-input>
</el-form-item>
<el-form-item label="Bucket所属地区">
<el-input v-model="dataForm.qcloudRegion" placeholder="如sh可选值 华南gz 华北tj 华东sh"></el-input>
</el-form-item>
</template>
</el-form>
<!-- 弹窗底部按钮 -->
<span slot="footer" class="dialog-footer">
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="dataFormSubmit()"></el-button>
</span>
</el-dialog> </el-dialog>
</template> </template>
<script> <script>
export default { export default {
data() { //
return { data() {
visible: false, return {
dataForm: {}, // /
dataRule: {} visible: false,
} //
}, dataForm: {},
methods: { //
init(id) { dataRule: {}
this.visible = true }
this.$http({ },
url: this.$http.adornUrl('/sys/oss/config'), methods: {
method: 'get', // id
params: this.$http.adornParams() init(id) {
}).then(({ data }) => { this.visible = true //
this.dataForm = data && data.code === 200 ? data.config : [] //
}) this.$http({
}, url: this.$http.adornUrl('/sys/oss/config'), //
// method: 'get', // GET
dataFormSubmit() { params: this.$http.adornParams() //
this.$refs['dataForm'].validate((valid) => { }).then(({ data }) => {
if (valid) { //
this.$http({ this.dataForm = data && data.code === 200 ? data.config : []
url: this.$http.adornUrl('/sys/oss/saveConfig'), })
method: 'post', },
data: this.$http.adornData(this.dataForm) //
}).then(({ data }) => { dataFormSubmit() {
if (data && data.code === 200) { //
this.$message({ this.$refs['dataForm'].validate((valid) => {
message: '操作成功', if (valid) {
type: 'success', //
duration: 1500, this.$http({
onClose: () => { url: this.$http.adornUrl('/sys/oss/saveConfig'), //
this.visible = false method: 'post', // POST
} data: this.$http.adornData(this.dataForm) //
}) }).then(({ data }) => {
} else { if (data && data.code === 200) {
this.$message.error(data.msg) //
} this.$message({
}) message: '操作成功',
} type: 'success',
}) duration: 1500,
} onClose: () => {
} this.visible = false //
}
})
} else {
//
this.$message.error(data.msg)
}
})
}
})
}
}
} }
</script> </script>

@ -1,87 +1,105 @@
<template> <template>
<div @click="selectFile"> <!-- 触发文件选择的区域点击时触发 selectFile 方法 -->
<input type="file" ref="fileInput" v-show="false" @change="onFileChange" /> <div @click="selectFile">
<div>{{uploading?infoText:'上传文件'}}</div> <!-- 隐藏的文件输入框通过 click 触发文件选择 -->
</div> <input type="file" ref="fileInput" v-show="false" @change="onFileChange" />
</template> <!-- 显示上传状态文本如果正在上传则显示 infoText否则显示 "上传文件" -->
<div>{{uploading ? infoText : '上传文件'}}</div>
<script> </div>
// 使 </template>
// 使 <script src="https://unpkg.com/cos-js-sdk-v5@0.5.23/dist/cos-js-sdk-v5.min.js" async></script>
<script>
// 使
// 使 SDKhttps://unpkg.com/cos-js-sdk-v5@0.5.23/dist/cos-js-sdk-v5.min.js
var cos; var cos;
export default { export default {
name: "oss-uploader", name: "oss-uploader", //
data() { data() {
return { return {
uploading: false, uploading: false, //
infoText:"上传中...", infoText: "上传中...", //
cosConfig:[] cosConfig: [] // COS
}
},
mounted(){
this.$http({
url: this.$http.adornUrl('/sys/oss/config'),
method: 'get',
params: this.$http.adornParams()
}).then(({data}) => {
if(data && data.code === 200){
this.cosConfig = data.config
cos=new COS({
SecretId: data.config.qcloudSecretId,
SecretKey: data.config.qcloudSecretKey,
});
}else{
this.$message.error('请先配置云存储相关信息!')
}
})
},
methods: {
selectFile() {//
if (!this.uploading) {
this.$refs.fileInput.click();
}
},
onFileChange() {
let file = this.$refs.fileInput.files[0];
this.uploading = true;
let now = new Date();
let path=now.toISOString().slice(0,10)+'/'+now.getTime()+file.name.substr(file.name.lastIndexOf('.'))
cos.putObject({
Bucket: this.cosConfig.qcloudBucketName, /* 必须 */
Region: this.cosConfig.qcloudRegion, /* 必须 */
Key: path, /* 必须 */
Body: file, //
onProgress: (progressData)=> {
this.infoText='上传中:'+progressData.percent*100+'%'
}
}, (err, data)=> {
console.log(err || data);
this.uploading = false;
if(data){
this.infoText='上传文件'
let fileUrl='https://'+this.cosConfig.qcloudBucketName+'.cos.'+this.cosConfig.qcloudRegion+'.myqcloud.com/'+path;
this.saveUploadResult(fileUrl)
}else {
this.$message.error('文件上传失败',err)
}
});
},
saveUploadResult(url){
this.$http({
url: this.$http.adornUrl('/sys/oss/upload'),
method: 'post',
data:{
url:url
}
}).then(({data})=>{
this.$emit('uploaded', url)
})
}
}
} }
</script> },
mounted() {
<style scoped> // COS
</style> this.$http({
url: this.$http.adornUrl('/sys/oss/config'),
method: 'get',
params: this.$http.adornParams() //
}).then(({ data }) => {
if (data && data.code === 200) {
//
this.cosConfig = data.config;
// COS
cos = new COS({
SecretId: data.config.qcloudSecretId,
SecretKey: data.config.qcloudSecretKey,
});
} else {
//
this.$message.error('请先配置云存储相关信息!');
}
})
},
methods: {
//
selectFile() {
//
if (!this.uploading) {
this.$refs.fileInput.click();
}
},
//
onFileChange() {
let file = this.$refs.fileInput.files[0]; //
this.uploading = true; // true
let now = new Date();
//
let path = now.toISOString().slice(0, 10) + '/' + now.getTime() + file.name.substr(file.name.lastIndexOf('.'));
// COS
cos.putObject({
Bucket: this.cosConfig.qcloudBucketName, //
Region: this.cosConfig.qcloudRegion, //
Key: path, //
Body: file, //
onProgress: (progressData) => { //
//
this.infoText = '上传中:' + (progressData.percent * 100).toFixed(2) + '%';
}
}, (err, data) => {
//
console.log(err || data);
this.uploading = false; // false
if (data) {
//
this.infoText = '上传文件';
// 访 URL
let fileUrl = 'https://' + this.cosConfig.qcloudBucketName + '.cos.' + this.cosConfig.qcloudRegion + '.myqcloud.com/' + path;
this.saveUploadResult(fileUrl); //
} else {
//
this.$message.error('文件上传失败', err);
}
});
},
// 访 URL
saveUploadResult(url) {
this.$http({
url: this.$http.adornUrl('/sys/oss/upload'),
method: 'post',
data: { url: url } // URL
}).then(({ data }) => {
// `uploaded` URL
this.$emit('uploaded', url);
})
}
}
}
</script>
<style scoped>
/* 样式部分为空 */
</style>

@ -1,59 +1,73 @@
<template> <template>
<!-- 点击外部div触发文件选择操作 -->
<div @click="selectFile"> <div @click="selectFile">
<input type="file" ref="fileInput" v-show="false" @change="onFileChange" /> <!-- 隐藏的文件上传input选择文件后触发onFileChange方法 -->
<div>{{uploading?infoText:'上传文件'}}</div> <input type="file" ref="fileInput" v-show="false" @change="onFileChange" />
<!-- 显示上传中的状态或默认的上传文件文本 -->
<div>{{uploading ? infoText : '上传文件'}}</div>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: "oss-uploader", name: "oss-uploader", // "oss-uploader"
data() { data() {
return { return {
uploading: false, uploading: false, // false
infoText: "上传中...", infoText: "上传中...", //
cosConfig: [] cosConfig: [] //
} }
}, },
mounted() { mounted() {
this.$http({ //
url: this.$http.adornUrl('/sys/oss/config'), this.$http({
method: 'get', url: this.$http.adornUrl('/sys/oss/config'), // API
params: this.$http.adornParams() method: 'get', // 使GET
}).then(({ data }) => { params: this.$http.adornParams() //
if (data && data.code === 200 && data.config.type) { }).then(({ data }) => {
this.cosConfig = data.config //
} else { if (data && data.code === 200 && data.config.type) {
this.$message.error('请先配置云存储相关信息!') this.cosConfig = data.config //
} } else {
//
}) this.$message.error('请先配置云存储相关信息!')
}
})
}, },
methods: { methods: {
selectFile() {// //
if (!this.uploading) { selectFile() {
this.$refs.fileInput.click(); if (!this.uploading) {
} // input
}, this.$refs.fileInput.click();
onFileChange() { }
let file = this.$refs.fileInput.files[0]; },
this.uploading = true; //
let formData = new FormData(); onFileChange() {
formData.append("file", file) let file = this.$refs.fileInput.files[0]; //
this.$http({ this.uploading = true; // true
url: this.$http.adornUrl('/sys/oss/upload'), let formData = new FormData();
method: 'post', formData.append("file", file); // formData
data: formData
}).then(({ data }) => { // POST
console.log(data) this.$http({
if (data && data.code === 200) { url: this.$http.adornUrl('/sys/oss/upload'), // API
this.$emit('uploaded', data.url) method: 'post', // 使POST
} else { data: formData //
this.$message.error("文件上传失败:" + data.msg) }).then(({ data }) => {
} //
this.uploading = false; console.log(data); // 便
}) if (data && data.code === 200) {
} // 'uploaded'url
this.$emit('uploaded', data.url)
} else {
//
this.$message.error("文件上传失败:" + data.msg)
}
this.uploading = false; // false
})
}
}
} }
} </script>
</script>

@ -39,108 +39,79 @@
<script> <script>
export default { export default {
data() { data() {
return { return {
dataForm: {}, //
dataList: [], dataForm: {},
pageIndex: 1, //
pageSize: 10, dataList: [],
totalCount: 0, //
dataListLoading: false, pageIndex: 1,
dataListSelections: [], //
configVisible: false, pageSize: 10,
uploadVisible: false //
} totalCount: 0,
}, //
components: { dataListLoading: false,
Config: () => import('./oss-config'), //
OssUploader: () => import('./oss-uploader') dataListSelections: [],
}, //
activated() { configVisible: false,
this.getDataList() //
}, uploadVisible: false
methods: { }
// },
getDataList() { components: {
this.dataListLoading = true //
this.$http({ Config: () => import('./oss-config'),
url: this.$http.adornUrl('/sys/oss/list'), //
method: 'get', OssUploader: () => import('./oss-uploader')
params: this.$http.adornParams({ },
'page': this.pageIndex, //
'limit': this.pageSize, activated() {
'sidx': 'id', this.getDataList();
'order': 'desc' },
}) methods: {
}).then(({ data }) => { //
if (data && data.code === 200) { getDataList() {
this.dataList = data.page.list this.dataListLoading = true;
this.totalCount = data.page.totalCount this.$http({
} else { url: this.$http.adornUrl('/sys/oss/list'),
this.dataList = [] method: 'get',
this.totalCount = 0 params: this.$http.adornParams({
} 'page': this.pageIndex, //
this.dataListLoading = false 'limit': this.pageSize, //
}) 'sidx': 'id', //
}, 'order': 'desc' //
// })
sizeChangeHandle(val) { }).then(({ data }) => {
this.pageSize = val // dataListtotalCount
this.pageIndex = 1 if (data && data.code === 200) {
this.getDataList() this.dataList = data.page.list;
}, this.totalCount = data.page.totalCount;
// } else {
currentChangeHandle(val) { //
this.pageIndex = val this.dataList = [];
this.getDataList() this.totalCount = 0;
}, }
// this.dataListLoading = false; //
selectionChangeHandle(val) { });
this.dataListSelections = val },
}, //
// sizeChangeHandle(val) {
configHandle() { this.pageSize = val;
this.configVisible = true this.pageIndex = 1; //
this.$nextTick(() => { this.getDataList(); //
this.$refs.config.init() },
}) //
}, currentChangeHandle(val) {
// this.pageIndex = val;
uploadHandle() { this.getDataList(); //
this.uploadVisible = true },
this.$nextTick(() => { //
this.$refs.upload.init() selectionChangeHandle(val) {
}) this.dataListSelections = val;
}, },
// }
deleteHandle(id) {
var ids = id ? [id] : this.dataListSelections.map(item => item.id)
this.$confirm(`确定对[id=${ids.join(',')}]进行[${id ? '删除' : '批量删除'}]操作?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$http({
url: this.$http.adornUrl('/sys/oss/delete'),
method: 'post',
data: this.$http.adornData(ids, false)
}).then(({ data }) => {
if (data && data.code === 200) {
this.$message({
message: '操作成功',
type: 'success',
duration: 1500,
onClose: () => this.getDataList()
})
} else {
this.$message.error(data.msg)
}
})
}).catch(() => { })
},
isImageUrl(url) {
return url && /.*\.(gif|jpg|jpeg|png|GIF|JPEG|JPG|PNG)/.test(url)
}
}
} }
</script> </script>

@ -1,96 +1,117 @@
<template> <template>
<el-dialog :title="!dataForm.id ? '新增' : '修改'" :close-on-click-modal="false" :visible.sync="visible"> <el-dialog :title="!dataForm.id ? '新增' : '修改'" :close-on-click-modal="false" :visible.sync="visible">
<el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmit()" label-width="80px"> <!-- 弹窗组件显示标题是新增修改取决于dataForm.id -->
<el-form-item label="参数名" prop="paramKey"> <el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmit()" label-width="80px">
<el-input v-model="dataForm.paramKey" placeholder="参数名"></el-input> <!-- 表单组件绑定数据模型为dataForm表单校验规则为dataRule按回车键提交表单 -->
</el-form-item>
<el-form-item label="参数值" prop="paramValue"> <el-form-item label="参数名" prop="paramKey">
<el-input v-model="dataForm.paramValue" placeholder="参数值"></el-input> <!-- 参数名输入框验证参数名 -->
</el-form-item> <el-input v-model="dataForm.paramKey" placeholder="参数名"></el-input>
<el-form-item label="备注" prop="remark"> </el-form-item>
<el-input v-model="dataForm.remark" placeholder="备注"></el-input>
</el-form-item> <el-form-item label="参数值" prop="paramValue">
</el-form> <!-- 参数值输入框验证参数值 -->
<span slot="footer" class="dialog-footer"> <el-input v-model="dataForm.paramValue" placeholder="参数值"></el-input>
<el-button @click="visible = false">取消</el-button> </el-form-item>
<el-button type="primary" @click="dataFormSubmit()"></el-button>
</span> <el-form-item label="备注" prop="remark">
</el-dialog> <!-- 备注输入框 -->
<el-input v-model="dataForm.remark" placeholder="备注"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<!-- 弹窗底部按钮 -->
<el-button @click="visible = false">取消</el-button>
<!-- 取消按钮点击时关闭弹窗 -->
<el-button type="primary" @click="dataFormSubmit()"></el-button>
<!-- 确定按钮点击时提交表单 -->
</span>
</el-dialog>
</template> </template>
<script> <script>
export default { export default {
data() { data() {
return { return {
visible: false, visible: false, //
dataForm: { dataForm: {
id: 0, id: 0, // ID0ID
paramKey: '', paramKey: '', //
paramValue: '', paramValue: '',//
remark: '' remark: '' //
}, },
dataRule: { dataRule: {
paramKey: [ paramKey: [
{ required: true, message: '参数名不能为空', trigger: 'blur' } { required: true, message: '参数名不能为空', trigger: 'blur' }
], ],
paramValue: [ paramValue: [
{ required: true, message: '参数值不能为空', trigger: 'blur' } { required: true, message: '参数值不能为空', trigger: 'blur' }
] ]
} }
} }
}, },
methods: { methods: {
init(id) { // ID
this.dataForm.id = id || 0 init(id) {
this.visible = true this.dataForm.id = id || 0
this.$nextTick(() => { this.visible = true
this.$refs['dataForm'].resetFields() this.$nextTick(() => {
if (this.dataForm.id) { this.$refs['dataForm'].resetFields() //
this.$http({ if (this.dataForm.id) {
url: this.$http.adornUrl(`/sys/config/info/${this.dataForm.id}`), //
method: 'get', this.$http({
params: this.$http.adornParams() url: this.$http.adornUrl(`/sys/config/info/${this.dataForm.id}`),
}).then(({ data }) => { method: 'get',
if (data && data.code === 200) { params: this.$http.adornParams()
this.dataForm.paramKey = data.config.paramKey }).then(({ data }) => {
this.dataForm.paramValue = data.config.paramValue if (data && data.code === 200) {
this.dataForm.remark = data.config.remark this.dataForm.paramKey = data.config.paramKey
} this.dataForm.paramValue = data.config.paramValue
}) this.dataForm.remark = data.config.remark
}
})
},
//
dataFormSubmit() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
this.$http({
url: this.$http.adornUrl(`/sys/config/${!this.dataForm.id ? 'save' : 'update'}`),
method: 'post',
data: this.$http.adornData({
'id': this.dataForm.id || undefined,
'paramKey': this.dataForm.paramKey,
'paramValue': this.dataForm.paramValue,
'remark': this.dataForm.remark
})
}).then(({ data }) => {
if (data && data.code === 200) {
this.$message({
message: '操作成功',
type: 'success',
duration: 1500,
onClose: () => {
this.visible = false
this.$emit('refreshDataList')
}
})
} else {
this.$message.error(data.msg)
}
})
}
})
}
}
} }
})
}
})
},
//
dataFormSubmit() {
//
this.$refs['dataForm'].validate((valid) => {
if (valid) {
//
this.$http({
url: this.$http.adornUrl(`/sys/config/${!this.dataForm.id ? 'save' : 'update'}`),
method: 'post',
data: this.$http.adornData({
'id': this.dataForm.id || undefined, // IDID
'paramKey': this.dataForm.paramKey,
'paramValue': this.dataForm.paramValue,
'remark': this.dataForm.remark
})
}).then(({ data }) => {
if (data && data.code === 200) {
//
this.$message({
message: '操作成功',
type: 'success',
duration: 1500,
onClose: () => {
this.visible = false
this.$emit('refreshDataList') //
}
})
} else {
//
this.$message.error(data.msg)
}
})
}
})
}
}
}
</script> </script>

@ -1,134 +1,172 @@
<template> <template>
<div class="mod-config"> <div class="mod-config">
<el-form :inline="true" :model="dataForm" @keyup.enter.native="getDataList()"> <!-- 表单部分包含参数名的查询框和操作按钮 -->
<el-form-item> <el-form :inline="true" :model="dataForm" @keyup.enter.native="getDataList()">
<el-input v-model="dataForm.paramKey" placeholder="参数名" clearable></el-input> <!-- 表单项使用 inline 布局按回车触发查询 -->
</el-form-item> <el-form-item>
<el-form-item> <el-input v-model="dataForm.paramKey" placeholder="参数名" clearable></el-input>
<el-button @click="getDataList()"></el-button> <!-- 输入框绑定 model dataForm.paramKey允许清除内容 -->
<el-button type="primary" @click="addOrUpdateHandle()"></el-button> </el-form-item>
<el-button type="danger" @click="deleteHandle()" :disabled="dataListSelections.length <= 0">批量删除</el-button> <el-form-item>
</el-form-item> <!-- 查询按钮点击时触发 getDataList 方法 -->
</el-form> <el-button @click="getDataList()"></el-button>
<el-table :data="dataList" border v-loading="dataListLoading" @selection-change="selectionChangeHandle" style="width: 100%;"> <!-- 新增按钮点击时触发 addOrUpdateHandle 方法 -->
<el-table-column type="selection" header-align="center" align="center" width="50"> <el-button type="primary" @click="addOrUpdateHandle()"></el-button>
</el-table-column> <!-- 批量删除按钮点击时触发 deleteHandle 方法只有当有选中的数据时可用 -->
<el-table-column prop="id" header-align="center" align="center" width="80" label="ID"> <el-button type="danger" @click="deleteHandle()" :disabled="dataListSelections.length <= 0">批量删除</el-button>
</el-table-column> </el-form-item>
<el-table-column prop="paramKey" header-align="center" align="center" label="参数名"> </el-form>
</el-table-column>
<el-table-column prop="paramValue" header-align="center" align="center" label="参数值"> <!-- 表格部分用于显示数据列表 -->
</el-table-column> <el-table :data="dataList" border v-loading="dataListLoading" @selection-change="selectionChangeHandle" style="width: 100%;">
<el-table-column prop="remark" header-align="center" align="center" label="备注"> <!-- 多选列 -->
</el-table-column> <el-table-column type="selection" header-align="center" align="center" width="50"></el-table-column>
<el-table-column fixed="right" header-align="center" align="center" width="150" label="操作">
<template slot-scope="scope"> <!-- ID列 -->
<el-button type="text" size="small" @click="addOrUpdateHandle(scope.row.id)"></el-button> <el-table-column prop="id" header-align="center" align="center" width="80" label="ID"></el-table-column>
<el-button type="text" size="small" @click="deleteHandle(scope.row.id)"></el-button>
</template> <!-- 参数名列 -->
</el-table-column> <el-table-column prop="paramKey" header-align="center" align="center" label="参数名"></el-table-column>
</el-table>
<el-pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" :current-page="pageIndex" :page-sizes="[10, 20, 50, 100]" :page-size="pageSize" :total="totalCount" layout="total, sizes, prev, pager, next, jumper"> <!-- 参数值列 -->
</el-pagination> <el-table-column prop="paramValue" header-align="center" align="center" label="参数值"></el-table-column>
<!-- 弹窗, 新增 / 修改 -->
<add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="getDataList"></add-or-update> <!-- 备注列 -->
</div> <el-table-column prop="remark" header-align="center" align="center" label="备注"></el-table-column>
<!-- 操作列包含修改和删除按钮 -->
<el-table-column fixed="right" header-align="center" align="center" width="150" label="操作">
<template slot-scope="scope">
<!-- 修改按钮点击时触发 addOrUpdateHandle 方法传入当前行的 id -->
<el-button type="text" size="small" @click="addOrUpdateHandle(scope.row.id)"></el-button>
<!-- 删除按钮点击时触发 deleteHandle 方法传入当前行的 id -->
<el-button type="text" size="small" @click="deleteHandle(scope.row.id)"></el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<el-pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" :current-page="pageIndex" :page-sizes="[10, 20, 50, 100]" :page-size="pageSize" :total="totalCount" layout="total, sizes, prev, pager, next, jumper">
</el-pagination>
<!-- 弹窗组件用于新增或修改数据 -->
<add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="getDataList"></add-or-update>
</div>
</template> </template>
<script> <script>
import AddOrUpdate from './config-add-or-update' import AddOrUpdate from './config-add-or-update'
export default { export default {
data() { data() {
return { return {
dataForm: { //
paramKey: '' dataForm: {
}, paramKey: ''
dataList: [], },
pageIndex: 1, //
pageSize: 10, dataList: [],
totalCount: 0, //
dataListLoading: false, pageIndex: 1,
dataListSelections: [], //
addOrUpdateVisible: false pageSize: 10,
} //
}, totalCount: 0,
components: { //
AddOrUpdate dataListLoading: false,
}, //
activated() { dataListSelections: [],
this.getDataList() // /
}, addOrUpdateVisible: false
methods: {
//
getDataList() {
this.dataListLoading = true
this.$http({
url: this.$http.adornUrl('/sys/config/list'),
method: 'get',
params: this.$http.adornParams({
'page': this.pageIndex,
'limit': this.pageSize,
'paramKey': this.dataForm.paramKey
})
}).then(({ data }) => {
if (data && data.code === 200) {
this.dataList = data.page.list
this.totalCount = data.page.totalCount
} else {
this.dataList = []
this.totalCount = 0
}
this.dataListLoading = false
})
},
//
sizeChangeHandle(val) {
this.pageSize = val
this.pageIndex = 1
this.getDataList()
},
//
currentChangeHandle(val) {
this.pageIndex = val
this.getDataList()
},
//
selectionChangeHandle(val) {
this.dataListSelections = val
},
// /
addOrUpdateHandle(id) {
this.addOrUpdateVisible = true
this.$nextTick(() => {
this.$refs.addOrUpdate.init(id)
})
},
//
deleteHandle(id) {
var ids = id ? [id] : this.dataListSelections.map(item => item.id)
this.$confirm(`确定对[id=${ids.join(',')}]进行[${id ? '删除' : '批量删除'}]操作?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$http({
url: this.$http.adornUrl('/sys/config/delete'),
method: 'post',
data: this.$http.adornData(ids, false)
}).then(({ data }) => {
if (data && data.code === 200) {
this.$message({
message: '操作成功',
type: 'success',
duration: 1500,
onClose: () => this.getDataList()
})
} else {
this.$message.error(data.msg)
}
})
}).catch(() => { })
}
}
} }
},
components: {
AddOrUpdate
},
activated() {
//
this.getDataList()
},
methods: {
//
getDataList() {
this.dataListLoading = true
this.$http({
url: this.$http.adornUrl('/sys/config/list'),
method: 'get',
params: this.$http.adornParams({
'page': this.pageIndex,
'limit': this.pageSize,
'paramKey': this.dataForm.paramKey
})
}).then(({ data }) => {
if (data && data.code === 200) {
this.dataList = data.page.list
this.totalCount = data.page.totalCount
} else {
this.dataList = []
this.totalCount = 0
}
this.dataListLoading = false
})
},
//
sizeChangeHandle(val) {
this.pageSize = val
this.pageIndex = 1
this.getDataList()
},
//
currentChangeHandle(val) {
this.pageIndex = val
this.getDataList()
},
//
selectionChangeHandle(val) {
this.dataListSelections = val
},
// /
addOrUpdateHandle(id) {
this.addOrUpdateVisible = true
this.$nextTick(() => {
// /
this.$refs.addOrUpdate.init(id)
})
},
//
deleteHandle(id) {
var ids = id ? [id] : this.dataListSelections.map(item => item.id)
//
this.$confirm(`确定对[id=${ids.join(',')}]进行[${id ? '删除' : '批量删除'}]操作?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$http({
url: this.$http.adornUrl('/sys/config/delete'),
method: 'post',
data: this.$http.adornData(ids, false)
}).then(({ data }) => {
if (data && data.code === 200) {
this.$message({
message: '操作成功',
type: 'success',
duration: 1500,
onClose: () => this.getDataList()
})
} else {
this.$message.error(data.msg)
}
})
}).catch(() => { })
}
}
}
</script> </script>

@ -1,90 +1,107 @@
<template> <template>
<div class="mod-log"> <div class="mod-log">
<el-form :inline="true" :model="dataForm" @keyup.enter.native="getDataList()"> <!-- 搜索表单部分 -->
<el-form-item> <el-form :inline="true" :model="dataForm" @keyup.enter.native="getDataList()">
<el-input v-model="dataForm.key" placeholder="用户名/用户操作" clearable></el-input> <!-- 输入框绑定到 dataForm.key用于搜索用户操作或者用户名 -->
</el-form-item> <el-form-item>
<el-form-item> <el-input v-model="dataForm.key" placeholder="用户名/用户操作" clearable></el-input>
<el-button @click="getDataList()"></el-button> </el-form-item>
</el-form-item> <el-form-item>
</el-form> <!-- 查询按钮点击时触发 getDataList 方法 -->
<el-table :data="dataList" border v-loading="dataListLoading" style="width: 100%"> <el-button @click="getDataList()"></el-button>
<el-table-column prop="id" header-align="center" align="center" width="80" label="ID"> </el-form-item>
</el-table-column> </el-form>
<el-table-column prop="username" header-align="center" align="center" label="用户名">
</el-table-column> <!-- 表格显示数据 -->
<el-table-column prop="operation" header-align="center" align="center" label="用户操作"> <el-table :data="dataList" border v-loading="dataListLoading" style="width: 100%">
</el-table-column> <!-- 表格的列定义 -->
<el-table-column prop="method" header-align="center" align="center" width="150" :show-overflow-tooltip="true" label="请求方法"> <el-table-column prop="id" header-align="center" align="center" width="80" label="ID"></el-table-column>
</el-table-column> <el-table-column prop="username" header-align="center" align="center" label="用户名"></el-table-column>
<el-table-column prop="params" header-align="center" align="center" width="150" :show-overflow-tooltip="true" label="请求参数"> <el-table-column prop="operation" header-align="center" align="center" label="用户操作"></el-table-column>
</el-table-column> <el-table-column prop="method" header-align="center" align="center" width="150" :show-overflow-tooltip="true" label="请求方法"></el-table-column>
<el-table-column prop="time" header-align="center" align="center" label="执行时长(毫秒)"> <el-table-column prop="params" header-align="center" align="center" width="150" :show-overflow-tooltip="true" label="请求参数"></el-table-column>
</el-table-column> <el-table-column prop="time" header-align="center" align="center" label="执行时长(毫秒)"></el-table-column>
<el-table-column prop="ip" header-align="center" align="center" width="150" label="IP地址"> <el-table-column prop="ip" header-align="center" align="center" width="150" label="IP地址"></el-table-column>
</el-table-column> <el-table-column prop="createDate" header-align="center" align="center" width="180" label="创建时间"></el-table-column>
<el-table-column prop="createDate" header-align="center" align="center" width="180" label="创建时间"> </el-table>
</el-table-column>
</el-table> <!-- 分页组件 -->
<el-pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" :current-page="pageIndex" :page-sizes="[10, 20, 50, 100]" :page-size="pageSize" :total="totalCount" layout="total, sizes, prev, pager, next, jumper"> <el-pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" :current-page="pageIndex" :page-sizes="[10, 20, 50, 100]" :page-size="pageSize" :total="totalCount" layout="total, sizes, prev, pager, next, jumper">
</el-pagination> </el-pagination>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
data() { data() {
return { return {
dataForm: { // 'key'
key: '' dataForm: {
}, key: ''
dataList: [], },
pageIndex: 1, //
pageSize: 10, dataList: [],
totalCount: 0, //
dataListLoading: false, pageIndex: 1,
selectionDataList: [] //
} pageSize: 10,
}, //
created() { totalCount: 0,
this.getDataList() //
}, dataListLoading: false,
methods: { // 使
// selectionDataList: []
getDataList() { }
this.dataListLoading = true },
this.$http({ created() {
url: this.$http.adornUrl('/sys/log/list'), //
method: 'get', this.getDataList()
params: this.$http.adornParams({ },
'page': this.pageIndex, methods: {
'limit': this.pageSize, //
'key': this.dataForm.key, getDataList() {
'sidx': 'id', //
'order': 'desc' this.dataListLoading = true
}) this.$http({
}).then(({ data }) => { url: this.$http.adornUrl('/sys/log/list'), //
if (data && data.code === 200) { method: 'get',
this.dataList = data.page.list params: this.$http.adornParams({
this.totalCount = data.page.totalCount //
} else { 'page': this.pageIndex,
this.dataList = [] 'limit': this.pageSize,
this.totalCount = 0 'key': this.dataForm.key, //
} 'sidx': 'id', // id
this.dataListLoading = false 'order': 'desc' //
}) })
}, }).then(({ data }) => {
// //
sizeChangeHandle(val) { if (data && data.code === 200) {
this.pageSize = val this.dataList = data.page.list //
this.pageIndex = 1 this.totalCount = data.page.totalCount //
this.getDataList() } else {
}, //
// this.dataList = []
currentChangeHandle(val) { this.totalCount = 0
this.pageIndex = val }
this.getDataList() //
} this.dataListLoading = false
} })
},
//
sizeChangeHandle(val) {
this.pageSize = val //
this.pageIndex = 1 //
this.getDataList() //
},
//
currentChangeHandle(val) {
this.pageIndex = val //
this.getDataList() //
}
} }
}
</script> </script>

@ -1,218 +1,253 @@
<template> <template>
<!-- 弹窗组件标题根据dataForm.id判断是新增还是修改 -->
<el-dialog :title="!dataForm.id ? '新增' : '修改'" :close-on-click-modal="false" :visible.sync="visible"> <el-dialog :title="!dataForm.id ? '新增' : '修改'" :close-on-click-modal="false" :visible.sync="visible">
<el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmit()" label-width="80px"> <!-- 表单组件绑定数据模型和验证规则 -->
<el-form-item label="类型" prop="type"> <el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmit()" label-width="80px">
<el-radio-group v-model="dataForm.type">
<el-radio v-for="(type, index) in dataForm.typeList" :label="index" :key="index">{{ type }}</el-radio> <!-- 菜单类型选择 -->
</el-radio-group> <el-form-item label="类型" prop="type">
</el-form-item> <el-radio-group v-model="dataForm.type">
<el-form-item :label="dataForm.typeList[dataForm.type] + '名称'" prop="name"> <!-- 循环渲染可选择的菜单类型 -->
<el-input v-model="dataForm.name" :placeholder="dataForm.typeList[dataForm.type] + '名称'"></el-input> <el-radio v-for="(type, index) in dataForm.typeList" :label="index" :key="index">{{ type }}</el-radio>
</el-form-item> </el-radio-group>
<el-form-item label="上级菜单" prop="parentName"> </el-form-item>
<el-popover ref="menuListPopover" placement="bottom-start" trigger="click">
<el-tree :data="menuList" :props="menuListTreeProps" node-key="menuId" ref="menuListTree" @current-change="menuListTreeCurrentChangeHandle" :default-expand-all="true" :highlight-current="true" :expand-on-click-node="false"> <!-- 菜单名称输入框 -->
</el-tree> <el-form-item :label="dataForm.typeList[dataForm.type] + '名称'" prop="name">
</el-popover> <el-input v-model="dataForm.name" :placeholder="dataForm.typeList[dataForm.type] + '名称'"></el-input>
<el-input v-model="dataForm.parentName" v-popover:menuListPopover :readonly="true" placeholder="点击选择上级菜单" class="menu-list__input"></el-input> </el-form-item>
</el-form-item>
<el-form-item v-if="dataForm.type === 1" label="菜单路由" prop="url"> <!-- 上级菜单选择 -->
<el-input v-model="dataForm.url" placeholder="菜单路由"></el-input> <el-form-item label="上级菜单" prop="parentName">
</el-form-item> <!-- 弹出菜单树选择 -->
<el-form-item v-if="dataForm.type !== 0" label="授权标识" prop="perms"> <el-popover ref="menuListPopover" placement="bottom-start" trigger="click">
<el-input v-model="dataForm.perms" placeholder="多个用逗号分隔, 如: user:list,user:create"></el-input> <el-tree :data="menuList" :props="menuListTreeProps" node-key="menuId" ref="menuListTree"
</el-form-item> @current-change="menuListTreeCurrentChangeHandle" :default-expand-all="true"
:highlight-current="true" :expand-on-click-node="false">
<el-form-item v-if="dataForm.type !== 2" label="菜单图标" prop="icon"> </el-tree>
<el-row> </el-popover>
<el-col :span="12"> <!-- 显示上级菜单选择 -->
<el-input v-model="dataForm.icon" placeholder="菜单图标名称" class="icon-list__input"></el-input> <el-input v-model="dataForm.parentName" v-popover:menuListPopover :readonly="true"
</el-col> placeholder="点击选择上级菜单" class="menu-list__input"></el-input>
<el-col :span="12" class="icon-list__tips"> </el-form-item>
<el-form-item v-if="dataForm.type !== 2" label="排序号" prop="orderNum">
<el-input-number v-model="dataForm.orderNum" controls-position="right" :min="0" label="排序号"></el-input-number> <!-- 菜单路由仅在选择菜单类型时显示 -->
</el-form-item> <el-form-item v-if="dataForm.type === 1" label="菜单路由" prop="url">
</el-col> <el-input v-model="dataForm.url" placeholder="菜单路由"></el-input>
</el-row> </el-form-item>
</el-form-item>
<div>参考ElementUI图标库, <a href="https://element.eleme.cn/#/zh-CN/component/icon" target="_blank">找图标</a></div> <!-- 授权标识仅在类型不为目录时显示 -->
</el-form> <el-form-item v-if="dataForm.type !== 0" label="授权标识" prop="perms">
<span slot="footer" class="dialog-footer"> <el-input v-model="dataForm.perms" placeholder="多个用逗号分隔, 如: user:list,user:create"></el-input>
<el-button @click="visible = false">取消</el-button> </el-form-item>
<el-button type="primary" @click="dataFormSubmit()"></el-button>
</span> <!-- 菜单图标仅在类型不为按钮时显示 -->
<el-form-item v-if="dataForm.type !== 2" label="菜单图标" prop="icon">
<el-row>
<el-col :span="12">
<el-input v-model="dataForm.icon" placeholder="菜单图标名称" class="icon-list__input"></el-input>
</el-col>
<el-col :span="12" class="icon-list__tips">
<!-- 排序号输入框仅在类型不为按钮时显示 -->
<el-form-item v-if="dataForm.type !== 2" label="排序号" prop="orderNum">
<el-input-number v-model="dataForm.orderNum" controls-position="right" :min="0" label="排序号"></el-input-number>
</el-form-item>
</el-col>
</el-row>
</el-form-item>
<!-- 提示用户参考图标库 -->
<div>参考ElementUI图标库, 找图标</div>
</el-form>
<!-- 弹窗底部按钮 -->
<span slot="footer" class="dialog-footer">
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="dataFormSubmit()"></el-button>
</span>
</el-dialog> </el-dialog>
</template> </template>
<script> <script>
import { treeDataTranslate } from '@/utils' //
export default { import { treeDataTranslate } from '@/utils'
export default {
data() { data() {
var validateUrl = (rule, value, callback) => { // URL
if (this.dataForm.type === 1 && !/\S/.test(value)) { var validateUrl = (rule, value, callback) => {
callback(new Error('菜单URL不能为空')) // URL
} else { if (this.dataForm.type === 1 && !/\S/.test(value)) {
callback() callback(new Error('菜单URL不能为空'))
} } else {
} callback() //
return { }
visible: false, }
dataForm: { return {
id: 0, visible: false, //
type: 1, dataForm: {
typeList: ['目录', '菜单', '按钮'], id: 0, // ID0
name: '', type: 1, // 0-1-2-
parentId: 0, typeList: ['目录', '菜单', '按钮'], //
parentName: '', name: '', //
url: '', parentId: 0, // ID
perms: '', parentName: '', //
orderNum: 0, url: '', //
icon: '', perms: '', //
}, orderNum: 0, //
dataRule: { icon: '', //
name: [ },
{ required: true, message: '菜单名称不能为空', trigger: 'blur' } //
], dataRule: {
parentName: [ name: [
{ required: true, message: '上级菜单不能为空', trigger: 'change' } { required: true, message: '菜单名称不能为空', trigger: 'blur' } //
], ],
url: [ parentName: [
{ validator: validateUrl, trigger: 'blur' } { required: true, message: '上级菜单不能为空', trigger: 'change' } //
] ],
}, url: [
menuList: [], { validator: validateUrl, trigger: 'blur' } // URL
menuListTreeProps: { ]
label: 'name', },
children: 'children' menuList: [], // 使
} menuListTreeProps: {
} label: 'name', //
children: 'children' //
}
}
}, },
methods: { methods: {
init(id) { //
this.dataForm.id = id || 0 init(id) {
this.$http({ this.dataForm.id = id || 0 // ID
url: this.$http.adornUrl('/sys/menu/select'), this.$http({
method: 'get', url: this.$http.adornUrl('/sys/menu/select'),
params: this.$http.adornParams() method: 'get',
}).then(({ data }) => { params: this.$http.adornParams()
this.menuList = treeDataTranslate(data.menuList, 'menuId') }).then(({ data }) => {
}).then(() => { //
this.visible = true this.menuList = treeDataTranslate(data.menuList, 'menuId')
this.$nextTick(() => { }).then(() => {
this.$refs['dataForm'].resetFields() this.visible = true //
}) this.$nextTick(() => {
}).then(() => { this.$refs['dataForm'].resetFields() //
if (!this.dataForm.id) { })
// }).then(() => {
this.menuListTreeSetCurrentNode() if (!this.dataForm.id) {
} else { //
// this.menuListTreeSetCurrentNode()
this.$http({ } else {
url: this.$http.adornUrl(`/sys/menu/info/${this.dataForm.id}`), //
method: 'get', this.$http({
params: this.$http.adornParams() url: this.$http.adornUrl(`/sys/menu/info/${this.dataForm.id}`),
}).then(({ data }) => { method: 'get',
this.dataForm.id = data.menu.menuId params: this.$http.adornParams()
this.dataForm.type = data.menu.type }).then(({ data }) => {
this.dataForm.name = data.menu.name //
this.dataForm.parentId = data.menu.parentId this.dataForm.id = data.menu.menuId
this.dataForm.url = data.menu.url this.dataForm.type = data.menu.type
this.dataForm.perms = data.menu.perms this.dataForm.name = data.menu.name
this.dataForm.orderNum = data.menu.orderNum this.dataForm.parentId = data.menu.parentId
this.dataForm.icon = data.menu.icon this.dataForm.url = data.menu.url
this.menuListTreeSetCurrentNode() this.dataForm.perms = data.menu.perms
}) this.dataForm.orderNum = data.menu.orderNum
} this.dataForm.icon = data.menu.icon
}) this.menuListTreeSetCurrentNode() //
}, })
// }
menuListTreeCurrentChangeHandle(data, node) { })
this.dataForm.parentId = data.menuId },
this.dataForm.parentName = data.name //
}, menuListTreeCurrentChangeHandle(data, node) {
// this.dataForm.parentId = data.menuId // ID
menuListTreeSetCurrentNode() { this.dataForm.parentName = data.name //
this.$refs.menuListTree.setCurrentKey(this.dataForm.parentId) },
this.dataForm.parentName = (this.$refs.menuListTree.getCurrentNode() || {})['name'] //
}, menuListTreeSetCurrentNode() {
// this.$refs.menuListTree.setCurrentKey(this.dataForm.parentId) //
dataFormSubmit() { this.dataForm.parentName = (this.$refs.menuListTree.getCurrentNode() || {})['name'] //
this.$refs['dataForm'].validate((valid) => { },
if (valid) { //
this.$http({ dataFormSubmit() {
url: this.$http.adornUrl(`/sys/menu/${!this.dataForm.id ? 'save' : 'update'}`), this.$refs['dataForm'].validate((valid) => {
method: 'post', if (valid) {
data: this.$http.adornData({ //
'menuId': this.dataForm.id || undefined, this.$http({
'type': this.dataForm.type, url: this.$http.adornUrl(`/sys/menu/${!this.dataForm.id ? 'save' : 'update'}`),
'name': this.dataForm.name, method: 'post',
'parentId': this.dataForm.parentId, data: this.$http.adornData({
'url': this.dataForm.url, 'menuId': this.dataForm.id || undefined,
'perms': this.dataForm.perms, 'type': this.dataForm.type,
'orderNum': this.dataForm.orderNum, 'name': this.dataForm.name,
'icon': this.dataForm.icon 'parentId': this.dataForm.parentId,
}) 'url': this.dataForm.url,
}).then(({ data }) => { 'perms': this.dataForm.perms,
if (data && data.code === 200) { 'orderNum': this.dataForm.orderNum,
this.$message({ 'icon': this.dataForm.icon
message: '操作成功', })
type: 'success', }).then(({ data }) => {
duration: 1500, if (data && data.code === 200) {
onClose: () => { //
this.visible = false this.$message({
this.$emit('refreshDataList') message: '操作成功',
} type: 'success',
}) duration: 1500,
} else { onClose: () => {
this.$message.error(data.msg) this.visible = false //
} this.$emit('refreshDataList') //
}) }
} })
}) } else {
} //
} this.$message.error(data.msg)
} }
</script> })
}
<style lang="scss"> })
.mod-menu { }
}
}
</script>
<style lang="scss">
.mod-menu {
.menu-list__input, .menu-list__input,
.icon-list__input { .icon-list__input {
> .el-input__inner { > .el-input__inner {
cursor: pointer; cursor: pointer; //
} }
} }
&__icon-popover { &__icon-popover {
width: 458px; width: 458px; //
overflow: hidden; overflow: hidden; //
} }
&__icon-inner { &__icon-inner {
width: 478px; width: 478px; //
max-height: 258px; max-height: 258px; //
overflow-x: hidden; overflow-x: hidden; //
overflow-y: auto; overflow-y: auto; //
} }
&__icon-list { &__icon-list {
width: 458px; width: 458px; //
padding: 0; padding: 0; //
margin: -8px 0 0 -8px; margin: -8px 0 0 -8px; //
> .el-button { > .el-button {
padding: 8px; padding: 8px; //
margin: 8px 0 0 8px; margin: 8px 0 0 8px; //
> span { > span {
display: inline-block; display: inline-block; // 使
vertical-align: middle; vertical-align: middle; //
width: 18px; width: 18px; //
height: 18px; height: 18px; //
font-size: 18px; font-size: 18px; //
} }
} }
} }
.icon-list__tips { .icon-list__tips {
font-size: 18px; font-size: 18px; //
text-align: center; text-align: center; //
color: #e6a23c; color: #e6a23c; //
cursor: pointer; cursor: pointer; //
}
} }
} </style>
</style>

@ -1,109 +1,148 @@
<template> <template>
<!-- 菜单管理模块 -->
<div class="mod-menu"> <div class="mod-menu">
<el-form :inline="true" :model="dataForm"> <!-- 表单组件内联布局 -->
<el-form-item> <el-form :inline="true" :model="dataForm">
<el-button v-if="isAuth('sys:menu:save')" type="primary" @click="addOrUpdateHandle()"></el-button> <el-form-item>
</el-form-item> <!-- 如果有新增权限显示新增按钮 -->
</el-form> <el-button v-if="isAuth('sys:menu:save')" type="primary" @click="addOrUpdateHandle()"></el-button>
</el-form-item>
<el-table :data="dataList" row-key="menuId" border style="width: 100%; "> </el-form>
<el-table-column prop="name" header-align="center" min-width="150" label="名称">
</el-table-column> <!-- 菜单数据表格 -->
<el-table-column prop="parentName" header-align="center" align="center" width="120" label="上级菜单"> <el-table :data="dataList" row-key="menuId" border style="width: 100%;">
</el-table-column> <!-- 菜单名称列 -->
<el-table-column header-align="center" align="center" label="图标"> <el-table-column prop="name" header-align="center" min-width="150" label="名称">
<template slot-scope="scope"> </el-table-column>
<i :class="scope.row.icon"></i>
</template> <!-- 上级菜单列 -->
</el-table-column> <el-table-column prop="parentName" header-align="center" align="center" width="120" label="上级菜单">
<el-table-column prop="type" header-align="center" align="center" label="类型"> </el-table-column>
<template slot-scope="scope">
<el-tag v-if="scope.row.type === 0" size="small"></el-tag> <!-- 菜单图标列 -->
<el-tag v-else-if="scope.row.type === 1" size="small" type="success">菜单</el-tag> <el-table-column header-align="center" align="center" label="图标">
<el-tag v-else-if="scope.row.type === 2" size="small" type="info">按钮</el-tag> <template slot-scope="scope">
</template> <!-- 根据图标类渲染图标 -->
</el-table-column> <i :class="scope.row.icon"></i>
<el-table-column prop="orderNum" header-align="center" align="center" label="排序号"> </template>
</el-table-column> </el-table-column>
<el-table-column prop="url" header-align="center" align="center" width="150" :show-overflow-tooltip="true" label="菜单URL">
</el-table-column> <!-- 菜单类型列 -->
<el-table-column prop="perms" header-align="center" align="center" width="150" :show-overflow-tooltip="true" label="授权标识"> <el-table-column prop="type" header-align="center" align="center" label="类型">
</el-table-column> <template slot-scope="scope">
<el-table-column fixed="right" header-align="center" align="center" width="150" label="操作"> <!-- 根据菜单类型渲染不同的标签 -->
<template slot-scope="scope"> <el-tag v-if="scope.row.type === 0" size="small"></el-tag>
<el-button v-if="isAuth('sys:menu:update')" type="text" size="small" @click="addOrUpdateHandle(scope.row.menuId)"></el-button> <el-tag v-else-if="scope.row.type === 1" size="small" type="success">菜单</el-tag>
<el-button v-if="isAuth('sys:menu:delete')" type="text" size="small" @click="deleteHandle(scope.row.menuId)"></el-button> <el-tag v-else-if="scope.row.type === 2" size="small" type="info">按钮</el-tag>
</template> </template>
</el-table-column> </el-table-column>
</el-table>
<!-- 弹窗, 新增 / 修改 --> <!-- 排序号列 -->
<add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="getDataList"></add-or-update> <el-table-column prop="orderNum" header-align="center" align="center" label="排序号">
</el-table-column>
<!-- 菜单URL列支持溢出提示 -->
<el-table-column prop="url" header-align="center" align="center" width="150" :show-overflow-tooltip="true" label="菜单URL">
</el-table-column>
<!-- 授权标识列支持溢出提示 -->
<el-table-column prop="perms" header-align="center" align="center" width="150" :show-overflow-tooltip="true" label="授权标识">
</el-table-column>
<!-- 操作列显示修改和删除按钮 -->
<el-table-column fixed="right" header-align="center" align="center" width="150" label="操作">
<template slot-scope="scope">
<!-- 如果有修改权限显示修改按钮 -->
<el-button v-if="isAuth('sys:menu:update')" type="text" size="small" @click="addOrUpdateHandle(scope.row.menuId)"></el-button>
<!-- 如果有删除权限显示删除按钮 -->
<el-button v-if="isAuth('sys:menu:delete')" type="text" size="small" @click="deleteHandle(scope.row.menuId)"></el-button>
</template>
</el-table-column>
</el-table>
<!-- 弹窗组件用于新增或修改菜单 -->
<add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="getDataList"></add-or-update>
</div> </div>
</template> </template>
<script> <script>
import AddOrUpdate from './menu-add-or-update' // /
import { treeDataTranslate } from '@/utils' import AddOrUpdate from './menu-add-or-update'
export default { import { treeDataTranslate } from '@/utils'
export default {
data() { data() {
return { return {
dataForm: {}, dataForm: {}, //
dataList: [], dataList: [], //
dataListLoading: false, dataListLoading: false, //
addOrUpdateVisible: false addOrUpdateVisible: false //
} }
}, },
components: { components: {
AddOrUpdate AddOrUpdate // /
}, },
activated() { activated() {
this.getDataList() //
this.getDataList()
}, },
methods: { methods: {
// //
getDataList() { getDataList() {
this.dataListLoading = true this.dataListLoading = true //
this.$http({ // HTTP
url: this.$http.adornUrl('/sys/menu/list'), this.$http({
method: 'get', url: this.$http.adornUrl('/sys/menu/list'),
params: this.$http.adornParams() method: 'get',
}).then(({ data }) => { params: this.$http.adornParams()
this.dataList = treeDataTranslate(data, 'menuId') }).then(({ data }) => {
this.dataListLoading = false // 使
}) this.dataList = treeDataTranslate(data, 'menuId')
}, this.dataListLoading = false //
// / })
addOrUpdateHandle(id) { },
this.addOrUpdateVisible = true
this.$nextTick(() => { //
this.$refs.addOrUpdate.init(id) addOrUpdateHandle(id) {
}) this.addOrUpdateVisible = true // /
}, this.$nextTick(() => {
// //
deleteHandle(id) { this.$refs.addOrUpdate.init(id)
this.$confirm(`确定对[id=${id}]进行[删除]操作?`, '提示', { })
confirmButtonText: '确定', },
cancelButtonText: '取消',
type: 'warning' //
}).then(() => { deleteHandle(id) {
this.$http({ //
url: this.$http.adornUrl(`/sys/menu/delete/${id}`), this.$confirm(`确定对[id=${id}]进行[删除]操作?`, '提示', {
method: 'post', confirmButtonText: '确定',
data: this.$http.adornData() cancelButtonText: '取消',
}).then(({ data }) => { type: 'warning' //
if (data && data.code === 200) { }).then(() => {
this.$message({ //
message: '操作成功', this.$http({
type: 'success', url: this.$http.adornUrl(`/sys/menu/delete/${id}`),
duration: 1500, method: 'post',
onClose: () => this.getDataList() data: this.$http.adornData()
}) }).then(({ data }) => {
} else { if (data && data.code === 200) {
this.$message.error(data.msg) //
} this.$message({
}) message: '操作成功',
}).catch(() => { }) type: 'success',
} duration: 1500,
onClose: () => this.getDataList() //
})
} else {
//
this.$message.error(data.msg)
}
})
}).catch(() => {
//
})
}
}
} }
} </script>
</script>

@ -1,111 +1,148 @@
<template> <template>
<!-- 弹窗组件显示角色的新增或修改表单 -->
<el-dialog :title="!dataForm.id ? '新增' : '修改'" :close-on-click-modal="false" :visible.sync="visible"> <el-dialog :title="!dataForm.id ? '新增' : '修改'" :close-on-click-modal="false" :visible.sync="visible">
<el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmit()" label-width="80px"> <!-- 表单组件绑定数据和验证规则 -->
<el-form-item label="角色名称" prop="roleName"> <el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmit()" label-width="80px">
<el-input v-model="dataForm.roleName" placeholder="角色名称"></el-input>
</el-form-item> <!-- 角色名称输入框 -->
<el-form-item label="备注" prop="remark"> <el-form-item label="角色名称" prop="roleName">
<el-input v-model="dataForm.remark" placeholder="备注"></el-input> <el-input v-model="dataForm.roleName" placeholder="角色名称"></el-input>
</el-form-item> </el-form-item>
<el-form-item size="mini" label="授权">
<el-tree :data="menuList" :props="menuListTreeProps" node-key="menuId" ref="menuListTree" :default-expand-all="true" show-checkbox> <!-- 备注输入框 -->
</el-tree> <el-form-item label="备注" prop="remark">
</el-form-item> <el-input v-model="dataForm.remark" placeholder="备注"></el-input>
</el-form> </el-form-item>
<span slot="footer" class="dialog-footer">
<el-button @click="visible = false">取消</el-button> <!-- 授权菜单树 -->
<el-button type="primary" @click="dataFormSubmit()"></el-button> <el-form-item size="mini" label="授权">
</span> <el-tree :data="menuList" :props="menuListTreeProps" node-key="menuId" ref="menuListTree" :default-expand-all="true" show-checkbox>
</el-tree>
</el-form-item>
</el-form>
<!-- 弹窗底部按钮取消和确认按钮 -->
<span slot="footer" class="dialog-footer">
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="dataFormSubmit()"></el-button>
</span>
</el-dialog> </el-dialog>
</template> </template>
<script> <script>
import { treeDataTranslate } from '@/utils' //
export default { import { treeDataTranslate } from '@/utils'
export default {
data() { data() {
return { return {
visible: false, //
menuList: [], visible: false,
menuListTreeProps: { //
label: 'name', menuList: [],
children: 'children' // el-tree
}, menuListTreeProps: {
dataForm: { label: 'name', //
id: 0, children: 'children' //
roleName: '', },
remark: '' //
}, dataForm: {
dataRule: { id: 0, // ID0
roleName: [ roleName: '', //
{ required: true, message: '角色名称不能为空', trigger: 'blur' } remark: '' //
] },
} //
} dataRule: {
roleName: [
{ required: true, message: '角色名称不能为空', trigger: 'blur' } //
]
}
}
}, },
methods: { methods: {
init(id) { // ID
this.dataForm.id = id || 0 init(id) {
this.$http({ this.dataForm.id = id || 0 // ID0
url: this.$http.adornUrl('/sys/menu/list'),
method: 'get', //
params: this.$http.adornParams() this.$http({
}).then(({ data }) => { url: this.$http.adornUrl('/sys/menu/list'),
this.menuList = treeDataTranslate(data, 'menuId') method: 'get',
}).then(() => { params: this.$http.adornParams()
this.visible = true }).then(({ data }) => {
this.$nextTick(() => { this.menuList = treeDataTranslate(data, 'menuId') //
this.$refs['dataForm'].resetFields() }).then(() => {
this.$refs.menuListTree.setCheckedKeys([]) //
}) this.visible = true
}).then(() => {
if (this.dataForm.id) { // DOM
this.$http({ this.$nextTick(() => {
url: this.$http.adornUrl(`/sys/role/info/${this.dataForm.id}`), //
method: 'get', this.$refs['dataForm'].resetFields()
params: this.$http.adornParams() //
}).then(({ data }) => { this.$refs.menuListTree.setCheckedKeys([])
if (data && data.code === 200) { })
this.dataForm.roleName = data.role.roleName }).then(() => {
this.dataForm.remark = data.role.remark // ID
data.role.menuIdList.forEach(item => { if (this.dataForm.id) {
this.$refs.menuListTree.setChecked(item, true); this.$http({
}); url: this.$http.adornUrl(`/sys/role/info/${this.dataForm.id}`),
} method: 'get',
}) params: this.$http.adornParams()
} }).then(({ data }) => {
}) if (data && data.code === 200) {
}, //
// this.dataForm.roleName = data.role.roleName
dataFormSubmit() { this.dataForm.remark = data.role.remark
this.$refs['dataForm'].validate((valid) => { //
if (valid) { data.role.menuIdList.forEach(item => {
this.$http({ this.$refs.menuListTree.setChecked(item, true)
url: this.$http.adornUrl(`/sys/role/${!this.dataForm.id ? 'save' : 'update'}`), })
method: 'post', }
data: this.$http.adornData({ })
'roleId': this.dataForm.id || undefined, }
'roleName': this.dataForm.roleName, })
'remark': this.dataForm.remark, },
'menuIdList': [].concat(this.$refs.menuListTree.getCheckedKeys(), this.$refs.menuListTree.getHalfCheckedKeys())
}) //
}).then(({ data }) => { dataFormSubmit() {
if (data && data.code === 200) { //
this.$message({ this.$refs['dataForm'].validate((valid) => {
message: '操作成功', if (valid) {
type: 'success', //
duration: 1500, this.$http({
onClose: () => { url: this.$http.adornUrl(`/sys/role/${!this.dataForm.id ? 'save' : 'update'}`), // ID
this.visible = false method: 'post',
this.$emit('refreshDataList') data: this.$http.adornData({
} 'roleId': this.dataForm.id || undefined, // ID
}) 'roleName': this.dataForm.roleName, //
} else { 'remark': this.dataForm.remark, //
this.$message.error(data.msg) // ID
} 'menuIdList': [].concat(this.$refs.menuListTree.getCheckedKeys(), this.$refs.menuListTree.getHalfCheckedKeys())
}) })
} }).then(({ data }) => {
}) if (data && data.code === 200) {
} //
this.$message({
message: '操作成功',
type: 'success',
duration: 1500,
onClose: () => {
//
this.visible = false
this.$emit('refreshDataList')
}
})
} else {
//
this.$message.error(data.msg)
}
})
}
})
}
}
} }
} </script>
</script>
Loading…
Cancel
Save