mirror of
https://gitee.com/lab1024/smart-admin.git
synced 2025-11-24 03:16:54 +08:00
v1.0.4
This commit is contained in:
33
smart-admin-web/src/views/api-doc/swagger.vue
Normal file
33
smart-admin-web/src/views/api-doc/swagger.vue
Normal file
@@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<div>
|
||||
<iframe :src="url" frameborder="0" height="800" scrolling="yes" width="100%"></iframe>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import config from '@/config';
|
||||
const baseUrl = config.baseUrl.apiUrl;
|
||||
export default {
|
||||
name: 'Swagger',
|
||||
components: {},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
url: baseUrl + '/swaggerApi'
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
filters: {},
|
||||
created() {},
|
||||
mounted() {},
|
||||
beforeCreate() {},
|
||||
beforeMount() {},
|
||||
beforeUpdate() {},
|
||||
updated() {},
|
||||
beforeDestroy() {},
|
||||
destroyed() {},
|
||||
activated() {},
|
||||
methods: {}
|
||||
};
|
||||
</script>
|
||||
214
smart-admin-web/src/views/email/email-list.vue
Normal file
214
smart-admin-web/src/views/email/email-list.vue
Normal file
@@ -0,0 +1,214 @@
|
||||
<template>
|
||||
<div>
|
||||
<Card class="warp-card" dis-hover>
|
||||
<Form :model="searchForm" class="tools" inline ref="searchForm">
|
||||
<FormItem prop="startDate">
|
||||
<DatePicker placeholder="请选择开始日期" type="datetime" v-model="searchForm.startDate"></DatePicker>
|
||||
</FormItem>
|
||||
<FormItem prop="endDate">
|
||||
<DatePicker placeholder="请选择截止日期" type="datetime" v-model="searchForm.endDate"></DatePicker>
|
||||
</FormItem>
|
||||
<FormItem prop="title">
|
||||
<Input placeholder="请输入标题" type="text" v-model="searchForm.title" />
|
||||
</FormItem>
|
||||
<FormItem prop="sendStatus">
|
||||
<Select style="width:200px" v-model="searchForm.sendStatus">
|
||||
<Option :value="1">已发送</Option>
|
||||
<Option :value="0">未发送</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<ButtonGroup>
|
||||
<Button @click="find" icon="ios-search" type="primary" v-privilege="'email-query'">查询</Button>
|
||||
<Button @click="reset" icon="md-refresh" type="default" v-privilege="'email-query'">重置</Button>
|
||||
</ButtonGroup>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button @click="addNew" icon="md-add" type="primary" v-privilege="'email-add'">新增</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<Table :columns="columns" :data="tableData"></Table>
|
||||
<Page
|
||||
:current="searchForm.pageNum"
|
||||
:page-size="searchForm.pageSize"
|
||||
:page-size-opts="[10, 20, 30, 50, 100]"
|
||||
:total="total"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
show-elevator
|
||||
show-sizer
|
||||
show-total
|
||||
style="margin:24px 0;text-align:right;"
|
||||
></Page>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { emailApi } from '@/api/email.js';
|
||||
export default {
|
||||
name: 'EmailList',
|
||||
components: {},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
// 数据量
|
||||
total: null,
|
||||
// 查询参数
|
||||
searchForm: {
|
||||
endDate: null,
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
searchCount: true, // 是否查询总条数
|
||||
sendStatus: null, // 发送状态 0未发送 1已发送
|
||||
startDate: null,
|
||||
title: null
|
||||
},
|
||||
// 表头
|
||||
columns: [
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'createTime'
|
||||
},
|
||||
{
|
||||
title: '发送状态',
|
||||
key: 'sendStatus',
|
||||
render(h, params) {
|
||||
let str = params.row.sendStatus == 0 ? '未发送' : '已发送';
|
||||
return h('span', {}, str);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '接收人',
|
||||
key: 'toEmails'
|
||||
},
|
||||
{
|
||||
title: '标题',
|
||||
key: 'title'
|
||||
},
|
||||
{
|
||||
title: '更新时间',
|
||||
key: 'updateTime'
|
||||
},
|
||||
{
|
||||
title: '邮件内容',
|
||||
key: 'content'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 160,
|
||||
align: 'center',
|
||||
className: 'action-hide',
|
||||
render: (h, params) => {
|
||||
return this.$tableAction(h, [
|
||||
{
|
||||
title: '编辑',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'email-update'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.editEmail(params);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '删除',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'email-delete'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.deleteEmail(params);
|
||||
}
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
],
|
||||
// table数据
|
||||
tableData: [],
|
||||
// 删除id
|
||||
delId: null
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
filters: {},
|
||||
created() {
|
||||
this.getEmailMess();
|
||||
},
|
||||
methods: {
|
||||
// 编辑邮件
|
||||
editEmail(params) {
|
||||
this.$router.push({
|
||||
path: '/email/send-mail',
|
||||
query: { id: params.row.id }
|
||||
});
|
||||
},
|
||||
// 新增
|
||||
addNew() {
|
||||
this.$router.push({ path: '/email/send-mail' });
|
||||
},
|
||||
// 重置
|
||||
reset() {
|
||||
this.$refs.searchForm.resetFields();
|
||||
this.searchForm.startDate = null;
|
||||
this.searchForm.endDate = null;
|
||||
this.$set(this.searchForm, 'endDate', null);
|
||||
this.find();
|
||||
},
|
||||
// 删除确定
|
||||
async deleteSure() {
|
||||
this.$Spin.show();
|
||||
let res = await emailApi.deleteEmail(this.delId);
|
||||
this.$Message.success('删除成功');
|
||||
this.$Spin.hide();
|
||||
this.getEmailMess();
|
||||
},
|
||||
// 删除操作
|
||||
deleteEmail(params) {
|
||||
this.delId = params.row.id;
|
||||
this.$Modal.confirm({
|
||||
title: '友情提醒',
|
||||
content: '确定要删除吗?',
|
||||
onOk: () => {
|
||||
this.deleteSure(params.row.id);
|
||||
}
|
||||
});
|
||||
},
|
||||
// 查询
|
||||
find() {
|
||||
this.searchForm.pageNum = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.getEmailMess();
|
||||
},
|
||||
// 更改分页查询条数
|
||||
changePageSize(pageSize) {
|
||||
this.searchForm.pageNum = 1;
|
||||
this.searchForm.pageSize = pageSize;
|
||||
this.getEmailMess();
|
||||
},
|
||||
// 获取邮件数据
|
||||
async getEmailMess() {
|
||||
this.$Spin.show();
|
||||
let res = await emailApi.getEmail(this.searchForm);
|
||||
this.$Spin.hide();
|
||||
this.tableData = res.data.list;
|
||||
this.total = res.data.total;
|
||||
if (res.data.pages < this.searchForm.pageNum) {
|
||||
this.searchForm.pageNum = res.data.pages;
|
||||
}
|
||||
},
|
||||
// 页码改变
|
||||
changePage(pageNum) {
|
||||
this.searchForm.pageNum = pageNum;
|
||||
this.getEmailMess();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
214
smart-admin-web/src/views/email/send-mail.vue
Normal file
214
smart-admin-web/src/views/email/send-mail.vue
Normal file
@@ -0,0 +1,214 @@
|
||||
<template>
|
||||
<div>
|
||||
<Card class="warp-card" dis-hover>
|
||||
<Form :label-width="80" :model="form" :rules="ruleInline">
|
||||
<FormItem class="marginBottom20" label="收件人" prop="toEmails">
|
||||
<Input class="addressWidth" placeholder="请输入对方邮箱" v-model="form.toEmails"></Input>
|
||||
</FormItem>
|
||||
<FormItem class="marginBottom20" label="标题" prop="title">
|
||||
<Input class="addressWidth" placeholder="请输入标题" v-model="form.title"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="内容" required>
|
||||
<div id="editor"></div>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button
|
||||
:loading="isShowSaveButtonLoading"
|
||||
@click="addOrUpdateEmail"
|
||||
type="primary"
|
||||
v-privilege="'email-send'"
|
||||
>保存</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import WangEditor from 'wangeditor';
|
||||
import Cookies from 'js-cookie';
|
||||
import config from '@/config';
|
||||
import { fileApi } from '@/api/file';
|
||||
import { emailApi } from '@/api/email';
|
||||
|
||||
const baseUrl = config.baseUrl.apiUrl;
|
||||
export default {
|
||||
name: 'SendMail',
|
||||
components: {},
|
||||
props: {},
|
||||
data() {
|
||||
let baseUrl = process.env.VUE_APP_URL;
|
||||
return {
|
||||
// loading
|
||||
isShowSaveButtonLoading: false,
|
||||
// 上传
|
||||
upload: {
|
||||
uploadList: [],
|
||||
data: {
|
||||
type: 'NEWS_PIC'
|
||||
}
|
||||
},
|
||||
// 富文本编辑器对象
|
||||
editor: null,
|
||||
// 基础路径
|
||||
baseUrl: baseUrl,
|
||||
// 传输内容
|
||||
form: {
|
||||
// 收件人
|
||||
toEmails: '',
|
||||
title: '',
|
||||
content: ''
|
||||
},
|
||||
// 验证规则
|
||||
ruleInline: {
|
||||
toEmails: [
|
||||
{ required: true, message: '请输入邮箱' },
|
||||
{ type: 'email', message: '请输入正确邮箱格式', trigger: 'blur' }
|
||||
],
|
||||
title: [{ required: true, message: '请输入标题', trigger: 'blur' }]
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
filters: {},
|
||||
created() {},
|
||||
mounted() {
|
||||
this.initEditor();
|
||||
this.getEmailDetails();
|
||||
},
|
||||
beforeCreate() {},
|
||||
beforeMount() {},
|
||||
beforeUpdate() {},
|
||||
updated() {},
|
||||
beforeDestroy() {},
|
||||
destroyed() {},
|
||||
activated() {},
|
||||
methods: {
|
||||
// 后退
|
||||
goBack() {
|
||||
this.$router.closeCurrentPage();
|
||||
},
|
||||
// 富文本初始化
|
||||
initEditor() {
|
||||
let g = this;
|
||||
g.editor = new WangEditor('#editor');
|
||||
g.editor.customConfig = {
|
||||
// 功能键
|
||||
menus: [
|
||||
'head', // 标题
|
||||
'bold', // 粗体
|
||||
'fontSize', // 字号
|
||||
'fontName', // 字体
|
||||
'italic', // 斜体
|
||||
'underline', // 下划线
|
||||
'strikeThrough', // 删除线
|
||||
'foreColor', // 文字颜色
|
||||
'backColor', // 背景颜色
|
||||
'list', // 列表
|
||||
'justify', // 对齐方式
|
||||
'emoticon', // 表情
|
||||
'image', // 插入图片
|
||||
'table', // 表格
|
||||
'undo', // 撤销
|
||||
'redo' // 重复
|
||||
],
|
||||
showLinkImg: false,
|
||||
uploadImgShowBase64: false,
|
||||
// 上传路径
|
||||
uploadImgServer: g.baseUrl + fileApi.fileUploadUrl + '1',
|
||||
// 上传文件名key
|
||||
uploadFileName: 'file',
|
||||
// 参数
|
||||
uploadImgParams: {
|
||||
'x-access-token': Cookies.get('token')
|
||||
},
|
||||
uploadImgHooks: {
|
||||
customInsert: function(insertImg, result, editor) {
|
||||
insertImg(result.data.url);
|
||||
}
|
||||
}
|
||||
};
|
||||
g.editor.create();
|
||||
},
|
||||
// 保存邮件
|
||||
addOrUpdateEmail() {
|
||||
// 富文本
|
||||
this.form.content = this.editor.txt.html();
|
||||
// 纯文本
|
||||
let newsId = this.$route.query.id;
|
||||
if (newsId) {
|
||||
// 编辑
|
||||
this.editEmail();
|
||||
} else {
|
||||
// 新增
|
||||
this.addNew();
|
||||
}
|
||||
},
|
||||
// 新增
|
||||
async addNew() {
|
||||
try {
|
||||
this.$Spin.show();
|
||||
this.isShowSaveButtonLoading = true;
|
||||
let res = await emailApi.addEmail(this.form);
|
||||
this.isShowSaveButtonLoading = false;
|
||||
let sendEmailResult = await emailApi.sendEmail(res.data);
|
||||
this.$Spin.hide();
|
||||
this.$Message.success('发送成功');
|
||||
this.goBack();
|
||||
} catch (error) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
this.isShowSaveButtonLoading = false;
|
||||
this.$Spin.hide();
|
||||
}
|
||||
},
|
||||
// 编辑
|
||||
async editEmail() {
|
||||
this.isShowSaveButtonLoading = true;
|
||||
this.$Spin.show();
|
||||
try {
|
||||
let res = await emailApi.updateEmail(this.form);
|
||||
this.isShowSaveButtonLoading = false;
|
||||
this.$Spin.hide();
|
||||
this.$Message.success('编辑成功');
|
||||
this.goBack();
|
||||
} catch (error) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
this.isShowSaveButtonLoading = false;
|
||||
} finally {
|
||||
this.$Spin.hide();
|
||||
}
|
||||
},
|
||||
// 获取详情
|
||||
async getEmailDetails() {
|
||||
this.$Spin.show();
|
||||
try {
|
||||
let id = this.$route.query.id;
|
||||
if (id) {
|
||||
let res = await emailApi.getEmailDetails(id);
|
||||
this.form = res.data;
|
||||
this.editor.txt.html(res.data.content);
|
||||
}
|
||||
} catch (error) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
} finally {
|
||||
this.$Spin.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.addressWidth {
|
||||
width: 350px;
|
||||
}
|
||||
.marginTop20 {
|
||||
margin-top: 20px;
|
||||
}
|
||||
.marginBottom20 {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,124 @@
|
||||
<template>
|
||||
<span @click="selectItem" style="display: inline-block">
|
||||
<span
|
||||
:style="itemData.selected ? selectStyle : currentStyle "
|
||||
@mouseout="onMouseout"
|
||||
@mouseover="onMouseover"
|
||||
>
|
||||
<Icon :type="itemData.icon" style="margin-right: 8px" />
|
||||
{{itemData.title}}
|
||||
</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'DepartmentEmployeeTreeItem',
|
||||
components: {},
|
||||
props: {
|
||||
// 数据样式 是否选中 图标
|
||||
// {
|
||||
// title: department.name,
|
||||
// icon: icon,
|
||||
// isEmployee: false,
|
||||
// id: department.id,
|
||||
// selectFunction: obj => {
|
||||
// if (this.isDepartment) {
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
itemData: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
// true 查部门
|
||||
isDepartment: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentStyle: {
|
||||
backgroundColor: '#FFF',
|
||||
color: '#495060',
|
||||
padding: '3px 8px'
|
||||
},
|
||||
hoverStyle: {
|
||||
backgroundColor: '#2d8cf0',
|
||||
color: '#FFF',
|
||||
padding: '3px 8px'
|
||||
},
|
||||
selectStyle: {
|
||||
backgroundColor: '#2d8cf0',
|
||||
color: '#FFF',
|
||||
padding: '3px 8px'
|
||||
},
|
||||
style: {
|
||||
backgroundColor: '#FFF',
|
||||
color: '#495060',
|
||||
padding: '3px 8px'
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
filters: {},
|
||||
created() {
|
||||
if (this.itemData.eventbus) {
|
||||
this.itemData.eventbus.$on('select', this.listenSelect);
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
beforeCreate() {},
|
||||
beforeMount() {},
|
||||
beforeUpdate() {},
|
||||
updated() {},
|
||||
beforeDestroy() {
|
||||
if (this.itemData.eventbus) {
|
||||
this.itemData.eventbus.$off('select', this.listenSelect);
|
||||
}
|
||||
},
|
||||
destroyed() {},
|
||||
activated() {},
|
||||
methods: {
|
||||
// 点击选中当前部门或成员
|
||||
selectItem() {
|
||||
if (
|
||||
(!this.isDepartment && this.itemData.isEmployee) ||
|
||||
this.isDepartment
|
||||
) {
|
||||
if (this.itemData.selectFunction) {
|
||||
this.itemData.selectFunction({
|
||||
id: this.itemData.id,
|
||||
name: this.itemData.title
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
//
|
||||
listenSelect(obj) {
|
||||
if (obj.id === this.itemData.id) {
|
||||
this.itemData.selected = true;
|
||||
} else {
|
||||
this.currentStyle = this.style;
|
||||
this.itemData.selected = false;
|
||||
}
|
||||
},
|
||||
// 鼠标移入效果
|
||||
onMouseover() {
|
||||
if (this.itemData.selected === null || !this.itemData.selected) {
|
||||
this.currentStyle = this.hoverStyle;
|
||||
}
|
||||
},
|
||||
// 鼠标移出效果
|
||||
onMouseout() {
|
||||
if (this.itemData.selected === null || !this.itemData.selected) {
|
||||
this.currentStyle = this.style;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
</style>
|
||||
@@ -0,0 +1,251 @@
|
||||
<template>
|
||||
<div style="height: 330px;">
|
||||
<Row>
|
||||
<Col span="24">
|
||||
<Input
|
||||
@on-change="filterEmployee"
|
||||
placeholder="请输入员工名称"
|
||||
style="max-width: 300px"
|
||||
v-if="!isDepartment"
|
||||
v-model="searchKeywords"
|
||||
/>
|
||||
<Tree :data="treeData"></Tree>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { departmentApi } from '@/api/department';
|
||||
import DepartmentEmployeeTreeItem from '../department-employee-tree-item/department-employee-tree-item.vue';
|
||||
import Vue from 'vue';
|
||||
export default {
|
||||
name: 'DepartmentEmployeeTree',
|
||||
components: {
|
||||
DepartmentEmployeeTreeItem
|
||||
},
|
||||
props: {
|
||||
// true 查部门
|
||||
isDepartment: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 查询部门及员工列表
|
||||
originalData: [],
|
||||
// 搜索内容
|
||||
searchKeywords: '',
|
||||
eventbus: new Vue(),
|
||||
// 当前树形选中 部门或人员
|
||||
currentSelect: null,
|
||||
// 生成适配的树形数据
|
||||
treeData: []
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
filters: {},
|
||||
created() {},
|
||||
mounted() {
|
||||
this.getDepartmentEmployeeList();
|
||||
},
|
||||
beforeCreate() {},
|
||||
beforeMount() {},
|
||||
beforeUpdate() {},
|
||||
updated() {},
|
||||
beforeDestroy() {},
|
||||
destroyed() {},
|
||||
activated() {},
|
||||
methods: {
|
||||
// 重置搜索内容
|
||||
resetSearch() {
|
||||
this.searchKeywords = '';
|
||||
this.getDepartmentEmployeeList();
|
||||
},
|
||||
// 获取当前选择项
|
||||
getSelect() {
|
||||
return this.currentSelect;
|
||||
},
|
||||
// 输入框输入后 搜索
|
||||
filterEmployee() {
|
||||
this.originalData.forEach(department => {
|
||||
this.recursionFilterEmployee(department);
|
||||
});
|
||||
this.generateTreeData();
|
||||
},
|
||||
// 根据searchKeywords搜索成员和部门
|
||||
recursionFilterEmployee(department) {
|
||||
if (department.employees) {
|
||||
department.employees.forEach(e => {
|
||||
if (
|
||||
this.searchKeywords === '' ||
|
||||
e.actualName.indexOf(this.searchKeywords) > -1
|
||||
) {
|
||||
e.show = true;
|
||||
} else {
|
||||
e.show = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (department.children) {
|
||||
department.children.forEach(item => {
|
||||
this.recursionFilterEmployee(item);
|
||||
});
|
||||
}
|
||||
},
|
||||
// 让所有部门展开所有子项
|
||||
filterDepartment() {
|
||||
this.originalData.forEach(department => {
|
||||
this.recursionFilterDepartment(department);
|
||||
});
|
||||
this.generateTreeData();
|
||||
},
|
||||
// 展开部门所有子项
|
||||
recursionFilterDepartment(department) {
|
||||
if (department.children) {
|
||||
department.children.forEach(e => {
|
||||
e.show = true;
|
||||
this.recursionFilterDepartment(e);
|
||||
});
|
||||
}
|
||||
},
|
||||
// 查询部门及员工列表
|
||||
async getDepartmentEmployeeList() {
|
||||
this.$Spin.show();
|
||||
let res = await departmentApi.getDepartmentEmployeeList();
|
||||
this.$Spin.hide();
|
||||
this.originalData = res.data;
|
||||
if (!this.isDepartment) {
|
||||
this.filterEmployee();
|
||||
} else {
|
||||
this.filterDepartment();
|
||||
}
|
||||
},
|
||||
// 生成树形图数据
|
||||
generateTreeData() {
|
||||
let tree = [];
|
||||
this.originalData.forEach(department => {
|
||||
let icon = department.type == 1 ? 'md-cube' : 'md-menu';
|
||||
let obj = Object.assign(
|
||||
{},
|
||||
{
|
||||
title: department.name,
|
||||
expand: true,
|
||||
children: this.constractTree(department),
|
||||
render: (h, { root, node, data }) => {
|
||||
return h(DepartmentEmployeeTreeItem, {
|
||||
props: {
|
||||
isDepartment: this.isDepartment,
|
||||
itemData: {
|
||||
title: department.name,
|
||||
icon: icon,
|
||||
isEmployee: false,
|
||||
id: department.id,
|
||||
selectFunction: obj => {
|
||||
if (this.isDepartment) {
|
||||
this.currentSelect = obj;
|
||||
this.eventbus.$emit('select', obj);
|
||||
this.$emit('on-select', obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
style: {
|
||||
cursor: 'pointer'
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
tree.push(obj);
|
||||
});
|
||||
this.treeData = tree;
|
||||
},
|
||||
// 根据部门构建树形
|
||||
constractTree(department) {
|
||||
let children = [];
|
||||
if (department.children) {
|
||||
department.children.forEach(departmentChild => {
|
||||
if (this.isDepartment && !departmentChild.show) {
|
||||
return;
|
||||
}
|
||||
let icon = departmentChild.type == 1 ? 'md-cube' : 'md-menu';
|
||||
let obj = Object.assign(
|
||||
{},
|
||||
{
|
||||
title: departmentChild.name,
|
||||
expand: true,
|
||||
disabled: false,
|
||||
children: this.constractTree(departmentChild),
|
||||
render: (h, { root, node, data }) => {
|
||||
return h(DepartmentEmployeeTreeItem, {
|
||||
props: {
|
||||
isDepartment: this.isDepartment,
|
||||
itemData: {
|
||||
title: departmentChild.name,
|
||||
icon: icon,
|
||||
isEmployee: false,
|
||||
id: departmentChild.id,
|
||||
selectFunction: obj => {
|
||||
this.currentSelect = obj;
|
||||
this.eventbus.$emit('select', obj);
|
||||
this.$emit('on-select', obj);
|
||||
}
|
||||
}
|
||||
},
|
||||
style: {
|
||||
cursor: 'pointer'
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
children.push(obj);
|
||||
});
|
||||
}
|
||||
if (!this.isDepartment && department.employees) {
|
||||
department.employees.forEach(employeeItem => {
|
||||
if (employeeItem.show) {
|
||||
let obj = Object.assign(
|
||||
{},
|
||||
{
|
||||
title: employeeItem.actualName,
|
||||
render: (h, { root, node, data }) => {
|
||||
return h(DepartmentEmployeeTreeItem, {
|
||||
props: {
|
||||
isDepartment: this.isDepartment,
|
||||
itemData: {
|
||||
title: employeeItem.actualName,
|
||||
icon: 'md-person',
|
||||
isEmployee: true,
|
||||
selected: false,
|
||||
id: employeeItem.id,
|
||||
eventbus: this.eventbus,
|
||||
selectFunction: obj => {
|
||||
this.currentSelect = obj;
|
||||
this.eventbus.$emit('select', obj);
|
||||
this.$emit('on-select', obj);
|
||||
}
|
||||
}
|
||||
},
|
||||
style: {
|
||||
cursor: 'pointer'
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
children.push(obj);
|
||||
}
|
||||
});
|
||||
}
|
||||
return children;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
</style>
|
||||
366
smart-admin-web/src/views/employee/position/position-list.vue
Normal file
366
smart-admin-web/src/views/employee/position/position-list.vue
Normal file
@@ -0,0 +1,366 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- Card 岗位管理内容区 start -->
|
||||
<Card class="warp-card" dis-hover>
|
||||
<!-- Form 搜索按钮区 start -->
|
||||
<Form class="tools" inline>
|
||||
<FormItem>
|
||||
<Input
|
||||
placeholder="请输入"
|
||||
v-model="searchFrom.positionName"
|
||||
v-privilege="'search-position'"
|
||||
>
|
||||
<Button @click="searchData" icon="ios-search" slot="append"></Button>
|
||||
</Input>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button
|
||||
@click="clearSearch"
|
||||
icon="md-refresh"
|
||||
type="default"
|
||||
v-privilege="'search-position'"
|
||||
>重置</Button>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button
|
||||
@click="isShowAddModal=true"
|
||||
icon="md-add"
|
||||
type="primary"
|
||||
v-privilege="'add-position'"
|
||||
>添加</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<!-- Form 搜索按钮区 end -->
|
||||
<Table :columns="columns" :data="data" :loading="isShowTablesLoading" ref="tablesMain"></Table>
|
||||
<Page
|
||||
:current="searchFrom.pageNum"
|
||||
:page-size="searchFrom.pageSize"
|
||||
:show-total="true"
|
||||
:total="pageTotal"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
style="margin:24px 0;text-align:right;"
|
||||
></Page>
|
||||
</Card>
|
||||
<!-- Card 内容区 end -->
|
||||
<!-- Modal 编辑岗位弹窗 start -->
|
||||
<Modal
|
||||
:loading="isShowUpdateLoading"
|
||||
@on-cancel="cancelUpdateData"
|
||||
@on-ok="validateAndUpdataPosition"
|
||||
title="编辑岗位"
|
||||
v-model="isShowEditModal"
|
||||
>
|
||||
<Form :label-width="80" :model="updateItem" :rules="updateValidate" ref="updateRef">
|
||||
<FormItem label="岗位名称" prop="positionName">
|
||||
<Input placeholder="请输入岗位名称(必填)" v-model="updateItem.positionName"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="岗位描述" prop="remark">
|
||||
<Input
|
||||
:autosize="{minRows: 4}"
|
||||
:maxlength="200"
|
||||
placeholder="请输入岗位描述(必填)"
|
||||
type="textarea"
|
||||
v-model="updateItem.remark "
|
||||
></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
<!-- Modal 编辑岗位弹窗 end -->
|
||||
<!-- Modal 添加岗位弹窗 start -->
|
||||
<Modal
|
||||
:loading="isShowSaveLoading"
|
||||
@on-cancel="cancelSaveData"
|
||||
@on-ok="validateAndAddPosition"
|
||||
title="添加岗位"
|
||||
v-model="isShowAddModal"
|
||||
>
|
||||
<Form :label-width="80" :model="saveItem" :rules="saveValidate" ref="saveRef">
|
||||
<FormItem label="岗位名称" prop="positionName">
|
||||
<Input :maxlength="30" placeholder="请输入岗位名称(必填)" v-model="saveItem.positionName"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="岗位描述" prop="remark">
|
||||
<Input
|
||||
:autosize="{minRows: 4}"
|
||||
:maxlength="200"
|
||||
placeholder="请输入岗位描述(必填)"
|
||||
type="textarea"
|
||||
v-model="saveItem.remark "
|
||||
></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
<!-- Modal 添加岗位弹窗 end -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { positionApi } from '@/api/position';
|
||||
export default {
|
||||
name: 'PositionList',
|
||||
components: {},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
isShowPage: true,
|
||||
searchValue: '',
|
||||
isShowEditModal: false,
|
||||
isShowAddModal: false,
|
||||
// table是否Loading
|
||||
isShowTablesLoading: true,
|
||||
isShowSaveLoading: true,
|
||||
isShowUpdateLoading: true,
|
||||
pageTotal: 0,
|
||||
// 更新的数据
|
||||
updateItem: {
|
||||
id: 0,
|
||||
positionName: 'positionName',
|
||||
remark: ''
|
||||
},
|
||||
// 添加保存的数据
|
||||
saveItem: {
|
||||
positionName: '',
|
||||
remark: ''
|
||||
},
|
||||
saveItemInt: {},
|
||||
// table表头
|
||||
columns: [
|
||||
{
|
||||
title: 'id',
|
||||
key: 'id',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '岗位名称',
|
||||
key: 'positionName',
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
title: '岗位描述',
|
||||
key: 'remark'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 150,
|
||||
align: 'center',
|
||||
className: 'action-hide',
|
||||
render: (h, params) => {
|
||||
return this.$tableAction(h, [
|
||||
{
|
||||
title: '编辑',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'update-position'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.updateItem = {
|
||||
id: params.row.id,
|
||||
positionName: params.row.positionName,
|
||||
remark: params.row.remark
|
||||
};
|
||||
this.isShowEditModal = true;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '删除',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'delete-position'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.$Modal.confirm({
|
||||
title: '友情提醒',
|
||||
content: '确定要删除吗?',
|
||||
onOk: () => {
|
||||
this.deletePositionById(params.row.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
],
|
||||
// table数据
|
||||
data: [],
|
||||
updateValidate: {
|
||||
positionName: [
|
||||
{ required: true, message: '请输入岗位名称', trigger: 'blur' }
|
||||
],
|
||||
remark: [{ required: true, message: '请输入岗位描述', trigger: 'blur' }]
|
||||
},
|
||||
saveValidate: {
|
||||
positionName: [
|
||||
{ required: true, message: '请输入岗位名称', trigger: 'blur' }
|
||||
],
|
||||
remark: [{ required: true, message: '请输入岗位描述', trigger: 'blur' }]
|
||||
},
|
||||
searchFrom: {
|
||||
positionName: '',
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
searchCount: true,
|
||||
sort: false
|
||||
},
|
||||
searchFromInt: {},
|
||||
isShowdeleteLoading: false
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
filters: {},
|
||||
created() {},
|
||||
mounted() {
|
||||
Object.assign(this.searchFromInt, this.searchFrom);
|
||||
Object.assign(this.saveItemInt, this.saveItem);
|
||||
this.getPositionListPage();
|
||||
},
|
||||
beforeCreate() {},
|
||||
beforeMount() {},
|
||||
beforeUpdate() {},
|
||||
updated() {},
|
||||
beforeDestroy() {},
|
||||
destroyed() {},
|
||||
activated() {},
|
||||
methods: {
|
||||
// 分页查询所有岗位
|
||||
async getPositionListPage() {
|
||||
try {
|
||||
this.isShowTablesLoading = true;
|
||||
this.isShowPage = true;
|
||||
let result = await positionApi.getPositionListPage(this.searchFrom);
|
||||
this.isShowTablesLoading = false;
|
||||
let datas = result.data;
|
||||
this.data = datas.list;
|
||||
this.pageTotal = datas.total;
|
||||
} catch (e) {
|
||||
this.isShowTablesLoading = false;
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
}
|
||||
},
|
||||
// 页码改变
|
||||
changePage(pageNum) {
|
||||
this.searchFrom.pageNum = pageNum;
|
||||
this.getPositionListPage();
|
||||
},
|
||||
// 改变每页显示数据条数
|
||||
changePageSize(pageSize) {
|
||||
this.searchFrom.pageNum = 1;
|
||||
this.searchFrom.pageSize = pageSize;
|
||||
this.getPositionListPage();
|
||||
},
|
||||
// 检验参数后 更新岗位
|
||||
validateAndUpdataPosition() {
|
||||
this.$refs['updateRef'].validate(valid => {
|
||||
this.isShowUpdateLoading = true;
|
||||
if (valid) {
|
||||
this.updatePosition();
|
||||
} else {
|
||||
this.isShowUpdateLoading = false;
|
||||
this.$nextTick(() => {
|
||||
this.isShowUpdateLoading = true;
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
// 更新岗位
|
||||
async updatePosition() {
|
||||
try {
|
||||
let result = await positionApi.updatePosition(this.updateItem);
|
||||
this.$Message.success('修改成功');
|
||||
await this.getPositionListPage();
|
||||
this.cancelUpdateData();
|
||||
} catch (e) {
|
||||
this.isShowUpdateLoading = false;
|
||||
this.$nextTick(() => {
|
||||
this.isShowUpdateLoading = true;
|
||||
});
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
} finally {
|
||||
this.isShowUpdateLoading = false;
|
||||
}
|
||||
},
|
||||
// 清除编辑模态框数据
|
||||
cancelUpdateData() {
|
||||
this.updateItem = {};
|
||||
// 清空form规则检查
|
||||
this.$refs['updateRef'].resetFields();
|
||||
this.isShowEditModal = false;
|
||||
},
|
||||
// 搜索
|
||||
searchData() {
|
||||
this.pageNum = 1;
|
||||
this.getPositionListPage();
|
||||
},
|
||||
// 重置
|
||||
clearSearch() {
|
||||
Object.assign(this.searchFrom, this.searchFromInt);
|
||||
this.getPositionListPage();
|
||||
},
|
||||
// 添加岗位
|
||||
validateAndAddPosition() {
|
||||
try {
|
||||
this.$refs['saveRef'].validate(valid => {
|
||||
this.isShowSaveLoading = true;
|
||||
if (valid) {
|
||||
this.addPosition();
|
||||
} else {
|
||||
this.isShowSaveLoading = false;
|
||||
this.$nextTick(() => {
|
||||
this.isShowSaveLoading = true;
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
}
|
||||
},
|
||||
// 添加岗位 - 异步
|
||||
async addPosition() {
|
||||
try {
|
||||
let result = await positionApi.addPosition(this.saveItem);
|
||||
this.$Message.success('添加成功');
|
||||
this.isShowSaveLoading = true;
|
||||
await this.getPositionListPage();
|
||||
this.cancelSaveData();
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
this.isShowSaveLoading = false;
|
||||
}
|
||||
},
|
||||
// 清除添加模态框数据
|
||||
cancelSaveData() {
|
||||
Object.assign(this.saveItem, this.saveItemInt);
|
||||
// 清空form规则检查
|
||||
this.$refs['saveRef'].resetFields();
|
||||
this.isShowAddModal = false;
|
||||
},
|
||||
// 根据ID删除岗位
|
||||
async deletePositionById(id) {
|
||||
try {
|
||||
this.isShowdeleteLoading = true;
|
||||
let result = await positionApi.deletePosition(id);
|
||||
this.isShowdeleteLoading = false;
|
||||
this.$Message.success('删除成功');
|
||||
await this.getPositionListPage();
|
||||
this.cancelSaveData();
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
this.isShowdeleteLoading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
</style>
|
||||
@@ -0,0 +1,527 @@
|
||||
<template>
|
||||
<div>
|
||||
<!--Modal 添加编辑成员 start-->
|
||||
<Modal
|
||||
:style="{top: '20px'}"
|
||||
:title="formValidate.id?'编辑成员':'添加成员'"
|
||||
@on-visible-change="onChangeVisibleModal"
|
||||
v-model="isShowAddOrUpdateEmployeeModal"
|
||||
width="740"
|
||||
>
|
||||
<div>
|
||||
<!--Form 添加编辑成员表单 start-->
|
||||
<Form :label-width="100" :model="formValidate" :rules="ruleValidate" ref="formValidate">
|
||||
<Row>
|
||||
<Col span="12">
|
||||
<FormItem label="登录名" prop="loginName">
|
||||
<Input
|
||||
:disabled="formValidate.id!=null"
|
||||
:maxlength="30"
|
||||
@on-keydown="formValidate.loginName=formValidate.loginName.replace(/^ +| +$/g,'')"
|
||||
@on-keyup="formValidate.loginName=formValidate.loginName.replace(/^ +| +$/g,'')"
|
||||
class="form-width"
|
||||
placeholder="请输入登录名"
|
||||
v-model="formValidate.loginName"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<FormItem label="姓名" prop="actualName">
|
||||
<Input
|
||||
:maxlength="30"
|
||||
@on-keydown="formValidate.actualName=formValidate.actualName.replace(/^ +| +$/g,'')"
|
||||
@on-keyup="formValidate.actualName=formValidate.actualName.replace(/^ +| +$/g,'')"
|
||||
class="form-width"
|
||||
placeholder="请输入姓名"
|
||||
v-model="formValidate.actualName"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<FormItem label="别名">
|
||||
<Input
|
||||
:maxlength="30"
|
||||
@on-keyup="formValidate.nickName=formValidate.nickName.replace(/^ +| +$/g,'')"
|
||||
class="form-width"
|
||||
placeholder="请输入别名"
|
||||
v-model="formValidate.nickName"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<FormItem label="身份证">
|
||||
<Input
|
||||
@on-blur="changeIdCard(formValidate.idCard)"
|
||||
@on-keyup="formValidate.idCard=formValidate.idCard.replace(/^ +| +$/g,'')"
|
||||
class="form-width"
|
||||
placeholder="请输入身份证信息"
|
||||
v-model="formValidate.idCard"
|
||||
></Input>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<FormItem label="手机" prop="phone">
|
||||
<Input
|
||||
@on-keyup="formValidate.phone=formValidate.phone.replace(/^ +| +$/g,'')"
|
||||
class="form-width"
|
||||
placeholder="请输入手机号"
|
||||
v-model="formValidate.phone"
|
||||
></Input>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<FormItem label="E-mail" prop="email">
|
||||
<Input
|
||||
class="form-width"
|
||||
placeholder="请输入邮箱地址"
|
||||
type="email"
|
||||
v-model="formValidate.email"
|
||||
></Input>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<FormItem
|
||||
class="select-class"
|
||||
label="部门"
|
||||
prop="departmentName"
|
||||
v-click-outside="clickOutside"
|
||||
>
|
||||
<Input
|
||||
@click.native="isShowTree = !isShowTree"
|
||||
class="form-width"
|
||||
placeholder="请选择部门"
|
||||
readonly
|
||||
v-model="formValidate.departmentName"
|
||||
>
|
||||
<Icon slot="suffix" type="ios-arrow-down" v-if="!isShowTree" />
|
||||
<Icon slot="suffix" type="ios-arrow-up" v-else />
|
||||
</Input>
|
||||
<div class="department-wrap" v-if="isShowTree">
|
||||
<DepartmentEmployeeTree
|
||||
:isDepartment="true"
|
||||
@on-select="selectDepartmentOrEmployee"
|
||||
ref="departmentEmployeeTree"
|
||||
></DepartmentEmployeeTree>
|
||||
</div>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<FormItem label="状态" required>
|
||||
<RadioGroup v-model="formValidate.isDisabled">
|
||||
<Radio :label="0">启用</Radio>
|
||||
<Radio :label="1">禁用</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span="24">
|
||||
<FormItem class="select-class" label="岗位" prop="positionIdList">
|
||||
<Select class="form-width" multiple v-model="formValidate.positionIdList">
|
||||
<Option
|
||||
:key="item.value"
|
||||
:value="item.value"
|
||||
v-for="item in positionListData"
|
||||
>{{ item.label }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<FormItem label="密码" prop="loginPwd" v-if="!formValidate.id">
|
||||
<Input
|
||||
@on-keydown="formValidate.loginPwd=formValidate.loginPwd.replace(/^ +| +$/g,'')"
|
||||
@on-keyup="formValidate.loginPwd=formValidate.loginPwd.replace(/^ +| +$/g,'')"
|
||||
class="form-width"
|
||||
placeholder="请输入密码"
|
||||
type="password"
|
||||
v-model="formValidate.loginPwd"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<FormItem label="密码确认" prop="passwordAgain" v-if="!formValidate.id">
|
||||
<Input
|
||||
@on-keydown="formValidate.passwordAgain=formValidate.passwordAgain.replace(/^ +| +$/g,'')"
|
||||
@on-keyup="formValidate.passwordAgain=formValidate.passwordAgain.replace(/^ +| +$/g,'')"
|
||||
class="form-width"
|
||||
placeholder="请输入确认密码"
|
||||
type="password"
|
||||
v-model="formValidate.passwordAgain"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
</Form>
|
||||
<!--Form 添加编辑成员表单 end-->
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<Button @click="isShowAddOrUpdateEmployeeModal=false" type="text">取消</Button>
|
||||
<Button :loading="isShowLoading" @click="submitFormData" class="newBtn" type="primary">提交</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
<!--Modal 添加编辑成员 end-->
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import $ from 'jquery';
|
||||
import { departmentApi } from '@/api/department';
|
||||
import { employeeApi } from '@/api/employee';
|
||||
import { roleApi } from '@/api/role';
|
||||
import { positionApi } from '@/api/position';
|
||||
import { dateFormat, utils } from '@/lib/util';
|
||||
import DepartmentEmployeeTree from '../../../components/department-employee-tree/department-employee-tree';
|
||||
export default {
|
||||
name: 'EmployeeTableAdd',
|
||||
components: {
|
||||
DepartmentEmployeeTree
|
||||
},
|
||||
props: {
|
||||
// 选中的部门
|
||||
selectDepartment: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isShowAddOrUpdateEmployeeModal: false,
|
||||
isShowLoading: false,
|
||||
roleList: [],
|
||||
positionListData: [],
|
||||
isShowTree: false,
|
||||
formValidateBackup: {},
|
||||
formValidate: {
|
||||
actualName: '',
|
||||
loginName: '',
|
||||
nickName: '',
|
||||
departmentName: '',
|
||||
departmentId: '',
|
||||
isDisabled: 0,
|
||||
phone: '',
|
||||
idCard: '',
|
||||
birthday: '',
|
||||
loginPwd: '',
|
||||
passwordAgain: '',
|
||||
email: '',
|
||||
positionIdList: []
|
||||
},
|
||||
ruleValidate: {
|
||||
loginName: [
|
||||
{ required: true, message: '登录名不能为空', trigger: 'blur' }
|
||||
],
|
||||
actualName: [
|
||||
{ required: true, message: '姓名不能为空', trigger: 'blur' }
|
||||
],
|
||||
idCard: [
|
||||
{ required: false, message: '身份证不能为空', trigger: 'blur' },
|
||||
{
|
||||
pattern: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/,
|
||||
message: '身份证格式错误',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
email: [
|
||||
{ required: false, message: '邮箱不能为空', trigger: 'blur' },
|
||||
{ type: 'email', message: '请输入正确邮箱格式', trigger: 'blur' }
|
||||
],
|
||||
departmentName: [
|
||||
{ required: true, message: '部门不能为空', trigger: 'blur' },
|
||||
{ required: true, message: '部门不能为空', trigger: 'change' }
|
||||
],
|
||||
positionIdList: [
|
||||
{
|
||||
required: true,
|
||||
type: 'array',
|
||||
min: 1,
|
||||
message: '岗位不能为空',
|
||||
trigger: 'change'
|
||||
}
|
||||
],
|
||||
birthday: [
|
||||
{ required: false, message: '请选择出生日期', trigger: 'blur' }
|
||||
],
|
||||
phone: [
|
||||
{ required: true, message: '手机号不能为空', trigger: 'blur' },
|
||||
{
|
||||
pattern: /^(13|14|15|16|17|18)\d{9}$/,
|
||||
message: '手机号格式错误',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
loginPwd: [
|
||||
{ required: true, message: '密码不能为空', trigger: 'blur' }
|
||||
],
|
||||
passwordAgain: [
|
||||
{ required: true, message: '确认密码不能为空', trigger: 'blur' }
|
||||
]
|
||||
},
|
||||
birthDate: {
|
||||
shortcuts: [
|
||||
{
|
||||
text: '今天',
|
||||
value() {
|
||||
return new Date();
|
||||
},
|
||||
onClick: picker => {
|
||||
this.$Message.info('你选择的是今天');
|
||||
}
|
||||
},
|
||||
{
|
||||
text: '昨天',
|
||||
value() {
|
||||
const date = new Date();
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24);
|
||||
return date;
|
||||
},
|
||||
onClick: picker => {
|
||||
this.$Message.info('你选择的是昨天');
|
||||
}
|
||||
},
|
||||
{
|
||||
text: '一周前',
|
||||
value() {
|
||||
const date = new Date();
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
|
||||
return date;
|
||||
},
|
||||
onClick: picker => {
|
||||
this.$Message.info('你选择的是一周前');
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {
|
||||
isShowAddOrUpdateEmployeeModal(val) {
|
||||
if (val) {
|
||||
this.getPositionListPage();
|
||||
}
|
||||
}
|
||||
},
|
||||
filters: {},
|
||||
created() {},
|
||||
mounted() {
|
||||
let dateStr = utils.getDateStr(0, dateFormat.YMDHM);
|
||||
this.formValidate.createDate = dateStr;
|
||||
Object.assign(this.formValidateBackup, this.formValidate);
|
||||
this.getAllRole();
|
||||
},
|
||||
beforeCreate() {},
|
||||
beforeMount() {},
|
||||
beforeUpdate() {},
|
||||
updated() {},
|
||||
beforeDestroy() {},
|
||||
destroyed() {},
|
||||
activated() {},
|
||||
methods: {
|
||||
// 选择部门点击外部关闭
|
||||
clickOutside() {
|
||||
if (this.isShowTree) {
|
||||
this.isShowTree = false;
|
||||
}
|
||||
},
|
||||
// 选择部门或者成员
|
||||
selectDepartmentOrEmployee(department) {
|
||||
this.$set(this.formValidate, 'departmentId', department.id);
|
||||
this.$set(this.formValidate, 'departmentName', department.name);
|
||||
this.isShowTree = false;
|
||||
$('.department-wrap').hide();
|
||||
},
|
||||
// 弹窗显示隐藏监听
|
||||
onChangeVisibleModal(value) {
|
||||
if (!value) {
|
||||
this.formValidate = Object.assign({}, this.formValidateBackup);
|
||||
}
|
||||
},
|
||||
// 打开Modal
|
||||
showModal(row) {
|
||||
if (typeof row === 'undefined') {
|
||||
this.ruleValidate.loginPwd = [
|
||||
{
|
||||
required: true,
|
||||
message: '密码长度至少为6位,不允许输入空格',
|
||||
trigger: 'blur',
|
||||
min: 6
|
||||
},
|
||||
{ pattern: /^[0-9]{6,10}$/, message: '密码格式错误', trigger: 'blur' }
|
||||
];
|
||||
this.ruleValidate.passwordAgain = [
|
||||
{ required: true, message: '确认密码不能为空', trigger: 'blur' },
|
||||
{
|
||||
validator: this.loginPwd,
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
pattern: /^[0-9]{6,10}$/,
|
||||
message: '确认密码格式错误',
|
||||
trigger: 'blur'
|
||||
}
|
||||
];
|
||||
this.ruleValidate.loginName = [
|
||||
{ required: true, message: '登录名不能为空', trigger: 'blur' },
|
||||
{
|
||||
pattern: /^[A-Za-z]+[A-Za-z0-9]{5,17}$/,
|
||||
message:
|
||||
'请输入6位或6位字符以上(英文+数字),第一个字符必须为英文字母',
|
||||
trigger: 'blur'
|
||||
}
|
||||
];
|
||||
} else {
|
||||
delete this.ruleValidate.loginPwd;
|
||||
delete this.ruleValidate.passwordAgain;
|
||||
this.ruleValidate.loginName = [
|
||||
{ required: true, message: '登录名不能为空', trigger: 'blur' }
|
||||
];
|
||||
}
|
||||
this.$refs['formValidate'].resetFields();
|
||||
if (row && Object.keys(row).length > 0) {
|
||||
let positionIdList = [];
|
||||
row.positionRelationList = row.positionRelationList || [];
|
||||
row.positionRelationList.map(item => {
|
||||
positionIdList.push(item.positionId);
|
||||
});
|
||||
row.positionIdList = positionIdList;
|
||||
this.formValidate = Object.assign({}, row);
|
||||
} else {
|
||||
if (Object.keys(this.selectDepartment).length > 0) {
|
||||
if (this.selectDepartment.type === 1) {
|
||||
this.formValidate.departmentId = null;
|
||||
this.formValidate.departmentName = null;
|
||||
this.formValidate.organizationId = this.selectDepartment.id;
|
||||
this.formValidate.organizationName = this.selectDepartment.name;
|
||||
} else {
|
||||
this.formValidate.departmentId = this.selectDepartment.id;
|
||||
this.formValidate.departmentName = this.selectDepartment.name;
|
||||
this.formValidate.organizationId = this.selectDepartment.organizationId;
|
||||
this.formValidate.organizationName = this.selectDepartment.organizationName;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.isShowAddOrUpdateEmployeeModal = true;
|
||||
},
|
||||
// 点击提交
|
||||
submitFormData() {
|
||||
this.$refs['formValidate'].validate(valid => {
|
||||
if (
|
||||
!/^[A-Za-z]+[A-Za-z0-9]{5,17}$/.test(this.formValidate.loginName) &&
|
||||
!this.formValidate.id
|
||||
) {
|
||||
this.$Message.error('登录名格式不正确!');
|
||||
return;
|
||||
}
|
||||
if (this.formValidate.idCard) {
|
||||
if (
|
||||
!/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(
|
||||
this.formValidate.idCard
|
||||
)
|
||||
) {
|
||||
this.$Message.error('身份证号码格式不正确!');
|
||||
return;
|
||||
}
|
||||
}
|
||||
const reg = new RegExp(
|
||||
"[`~!@#$^&*()=|{}':;',\\[\\].<>/?~!@#¥……&*()——|{}【】‘;:”“'。,、?]"
|
||||
);
|
||||
if (reg.test(this.formValidate.actualName)) {
|
||||
this.$Message.error('姓名中不能含有特殊字符!');
|
||||
return false;
|
||||
}
|
||||
if (this.formValidate.passwordAgain !== this.formValidate.loginPwd) {
|
||||
this.$Message.error('两次输入密码不一致,请重新输入!!');
|
||||
return;
|
||||
}
|
||||
if (valid) {
|
||||
if (this.formValidate.id) {
|
||||
this.updateEmployee(this.formValidate);
|
||||
} else {
|
||||
this.addEmployee(this.formValidate);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
// 修改成员
|
||||
async updateEmployee(data) {
|
||||
try {
|
||||
this.isShowLoading = true;
|
||||
let result = await employeeApi.updateEmployee(data);
|
||||
this.isShowAddOrUpdateEmployeeModal = false;
|
||||
this.$Message.success('修改成员成功');
|
||||
this.$emit('addSuccess');
|
||||
this.$refs['formValidate'].resetFields();
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
} finally {
|
||||
this.isShowLoading = false;
|
||||
}
|
||||
},
|
||||
// 添加新用户接口
|
||||
async addEmployee(param) {
|
||||
try {
|
||||
this.isShowLoading = true;
|
||||
let result = await employeeApi.addEmployee(param);
|
||||
this.isShowAddOrUpdateEmployeeModal = false;
|
||||
this.$Message.success('添加成员成功');
|
||||
this.$emit('addSuccess');
|
||||
this.$refs['formValidate'].resetFields();
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
} finally {
|
||||
this.isShowLoading = false;
|
||||
}
|
||||
},
|
||||
// 加载角色列表
|
||||
async getAllRole() {
|
||||
let result = await roleApi.getAllRole();
|
||||
this.roleList = result.data;
|
||||
},
|
||||
// 分页查询所有岗位
|
||||
async getPositionListPage() {
|
||||
let result = await positionApi.getPositionListPage({
|
||||
pageNum: 1,
|
||||
pageSize: 200,
|
||||
sort: false
|
||||
});
|
||||
let datas = result.data;
|
||||
let list = [];
|
||||
datas.list.map(item => {
|
||||
list.push({
|
||||
value: item.id,
|
||||
label: item.positionName
|
||||
});
|
||||
});
|
||||
this.positionListData = list;
|
||||
},
|
||||
// 身份证输入失焦校验
|
||||
changeIdCard(value) {
|
||||
let reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
|
||||
if (reg.test(value)) {
|
||||
let data = value.slice(6, 14);
|
||||
let y = data.slice(0, 4);
|
||||
let m = data.slice(4, 6);
|
||||
let d = data.slice(6, 8);
|
||||
this.formValidate.birthday = y + '-' + m + '-' + d;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.form-width {
|
||||
width: 100%;
|
||||
}
|
||||
.department-wrap {
|
||||
position: absolute;
|
||||
background-color: #ffffff;
|
||||
padding: 5px;
|
||||
border: 1px solid #dedede;
|
||||
width: 300px;
|
||||
z-index: 9;
|
||||
height: 250px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.select-class {
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,72 @@
|
||||
<template>
|
||||
<Modal :footer-hide="true" :width="700" title="职员详情" v-model="isShowDetailModal">
|
||||
<Form :label-width="80">
|
||||
<Row :gutter="16">
|
||||
<Col span="8">
|
||||
<FormItem label="姓名:">{{detail.actualName}}</FormItem>
|
||||
</Col>
|
||||
<Col span="8">
|
||||
<FormItem label="登录名:">{{detail.loginName}}</FormItem>
|
||||
</Col>
|
||||
<Col span="8">
|
||||
<FormItem label="别名:">{{detail.nickName}}</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row :gutter="16">
|
||||
<Col span="8">
|
||||
<FormItem label="部门:">{{detail.departmentName}}</FormItem>
|
||||
</Col>
|
||||
<Col span="8">
|
||||
<FormItem label="手机:">{{detail.phone}}</FormItem>
|
||||
</Col>
|
||||
<Col span="8">
|
||||
<FormItem label="身份证:">{{detail.idCard}}</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row :gutter="16">
|
||||
<Col span="8">
|
||||
<FormItem label="出生日期:">{{detail.birthday}}</FormItem>
|
||||
</Col>
|
||||
<Col span="8">
|
||||
<FormItem label="电子邮箱:">{{detail.email}}</FormItem>
|
||||
</Col>
|
||||
<Col span="8">
|
||||
<FormItem label="状态:">{{detail.isDisabled?"禁用":"启用"}}</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
</Form>
|
||||
</Modal>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'EmployeeTableDetail',
|
||||
components: {},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
isShowDetailModal: false,
|
||||
detail: {}
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
filters: {},
|
||||
created() {},
|
||||
mounted() {},
|
||||
beforeCreate() {},
|
||||
beforeMount() {},
|
||||
beforeUpdate() {},
|
||||
updated() {},
|
||||
beforeDestroy() {},
|
||||
destroyed() {},
|
||||
activated() {},
|
||||
methods: {
|
||||
showModal(detail) {
|
||||
this.isShowDetailModal = true;
|
||||
this.detail = detail;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
</style>
|
||||
@@ -0,0 +1,569 @@
|
||||
<template>
|
||||
<div>
|
||||
<Col :lg="19" :md="16">
|
||||
<Card class="warp-card" dis-hover>
|
||||
<!--Row 顶部操作区 start-->
|
||||
<Row justify="space-between" type="flex">
|
||||
<Col>
|
||||
<Input
|
||||
@on-change="searchEmployees"
|
||||
icon="md-search"
|
||||
placeholder="请输入姓名搜搜..."
|
||||
style="width: 200px"
|
||||
v-model="searchEmployeeName"
|
||||
/>
|
||||
<Button
|
||||
@click="showAddEmployeeModal"
|
||||
icon="md-add"
|
||||
style="margin-left: 5px;"
|
||||
type="primary"
|
||||
v-privilege="'add-employee'"
|
||||
>添加成员</Button>
|
||||
</Col>
|
||||
<Col>
|
||||
<Button
|
||||
@click="queryEmployeeListByIsDisabled(1)"
|
||||
type="default"
|
||||
v-privilege="'search-department'"
|
||||
v-show="!currentDisabled"
|
||||
>查看已禁用用户</Button>
|
||||
<Button
|
||||
@click="queryEmployeeListByIsDisabled(0)"
|
||||
type="default"
|
||||
v-privilege="'search-department'"
|
||||
v-show="currentDisabled"
|
||||
>查看已启用用户</Button>
|
||||
<Button
|
||||
@click="GroupDisable(1)"
|
||||
style="margin-left:5px"
|
||||
type="error"
|
||||
v-privilege="'disabled-employee-batch'"
|
||||
v-show="!currentDisabled"
|
||||
>批量禁用</Button>
|
||||
<Button
|
||||
@click="GroupDisable(0)"
|
||||
style="margin-left:5px"
|
||||
type="success"
|
||||
v-privilege="'disabled-employee-batch'"
|
||||
v-show="currentDisabled"
|
||||
>批量启用</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
<!--Row 顶部操作区 end-->
|
||||
<!--Row 表格区 start-->
|
||||
<Row style="padding-top:10px; ">
|
||||
<Table
|
||||
:columns="columns"
|
||||
:data="employeeTable"
|
||||
:loading="isShowTablesLoading"
|
||||
@on-selection-change="singleSelect"
|
||||
border
|
||||
></Table>
|
||||
</Row>
|
||||
<!--Row 表格区 end-->
|
||||
<!--Row 底部操作区 start-->
|
||||
<Row class="page" justify="end" style="position: relative;margin-top: 10px;" type="flex">
|
||||
<Page
|
||||
:current="pageNum"
|
||||
:page-size="pageSize"
|
||||
:total="totalPage"
|
||||
@on-change="changePage"
|
||||
show-elevator
|
||||
></Page>
|
||||
</Row>
|
||||
<!--Row 底部操作区 end-->
|
||||
</Card>
|
||||
</Col>
|
||||
<!--EmployeeTableAdd 添加成员弹窗 start-->
|
||||
<EmployeeTableAdd
|
||||
:selectDepartment="selectDepartment"
|
||||
@addSuccess="getEmployeeList"
|
||||
ref="employeeTableAdd"
|
||||
></EmployeeTableAdd>
|
||||
<!--EmployeeTableAdd 添加成员弹窗 end-->
|
||||
<!--Modal 角色管理弹窗 start-->
|
||||
<Modal
|
||||
@on-ok="confirmAddRole"
|
||||
class-name="vertical-center-modal"
|
||||
title="角色管理"
|
||||
v-model="isShowManageRoleModal"
|
||||
>
|
||||
<CheckboxGroup v-model="employeeRole">
|
||||
<Checkbox
|
||||
:key="roleItem.id"
|
||||
:label="roleItem.id"
|
||||
style="width:104px;line-height:40px;"
|
||||
v-for="roleItem in roleList"
|
||||
>{{roleItem.roleName}}</Checkbox>
|
||||
</CheckboxGroup>
|
||||
</Modal>
|
||||
<!--Modal 角色管理弹窗 end-->
|
||||
<!--EmployeeTableDetail 角色详情 start-->
|
||||
<EmployeeTableDetail ref="employeeTableDetail"></EmployeeTableDetail>
|
||||
<!--EmployeeTableDetail 角色详情 end-->
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { departmentApi } from '@/api/department';
|
||||
import { employeeApi } from '@/api/employee';
|
||||
import { roleApi } from '@/api/role';
|
||||
import { utils } from '@/lib/util';
|
||||
import EmployeeTableAdd from '../employee-table-add/employee-table-add.vue';
|
||||
import EmployeeTableDetail from '../employee-table-detail/employee-table-detail.vue';
|
||||
export default {
|
||||
name: 'EmployeeTable',
|
||||
components: {
|
||||
EmployeeTableAdd,
|
||||
EmployeeTableDetail
|
||||
},
|
||||
props: {
|
||||
// 选中的部门
|
||||
selectDepartment: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
// 表格样式 按钮功能
|
||||
departments: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
employeeRole: [],
|
||||
// 员工id
|
||||
mid: '',
|
||||
totalPage: 0,
|
||||
pageSize: 10,
|
||||
pageNum: 1,
|
||||
isShowManageRoleModal: false,
|
||||
isShowTablesLoading: false,
|
||||
// 搜索框内容
|
||||
searchEmployeeName: '',
|
||||
columns: [
|
||||
{
|
||||
type: 'selection',
|
||||
width: 60,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: 'ID',
|
||||
width: 60,
|
||||
key: 'id'
|
||||
},
|
||||
{
|
||||
key: 'actualName',
|
||||
width: 200,
|
||||
title: '名称',
|
||||
align: 'left'
|
||||
},
|
||||
{
|
||||
key: 'loginName',
|
||||
title: '登录名',
|
||||
width: 200,
|
||||
align: 'left'
|
||||
},
|
||||
{
|
||||
key: 'isDisabled',
|
||||
width: 80,
|
||||
title: '状态',
|
||||
align: 'left',
|
||||
render: (h, params) => {
|
||||
let disabled = params.row.isDisabled;
|
||||
return h('span', disabled ? '禁用' : '启用');
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'phone',
|
||||
width: 120,
|
||||
title: '手机',
|
||||
align: 'left'
|
||||
},
|
||||
{
|
||||
key: 'departmentName',
|
||||
width: 180,
|
||||
title: '所属部门',
|
||||
align: 'left'
|
||||
},
|
||||
{
|
||||
key: 'positionName',
|
||||
width: 180,
|
||||
title: '岗位',
|
||||
align: 'left',
|
||||
ellipsis: true,
|
||||
tooltip: true
|
||||
},
|
||||
{
|
||||
key: 'email',
|
||||
width: 180,
|
||||
title: '电子邮箱',
|
||||
align: 'left'
|
||||
},
|
||||
|
||||
{
|
||||
key: 'createTime',
|
||||
width: 180,
|
||||
title: '创建时间',
|
||||
align: 'left'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 160,
|
||||
fixed: 'right',
|
||||
align: 'center',
|
||||
className: 'action-hide',
|
||||
render: (h, params) => {
|
||||
let btnGroup = [];
|
||||
let isSuper = params.row.super;
|
||||
if (!isSuper) {
|
||||
btnGroup.push({
|
||||
title: '角色设置',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'update-employee-role'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.showManageRoleModal(h, params);
|
||||
}
|
||||
});
|
||||
}
|
||||
btnGroup.push({
|
||||
title: '详情',
|
||||
action: () => {
|
||||
this.$refs['employeeTableDetail'].showModal(params.row);
|
||||
}
|
||||
});
|
||||
if (params.row.isDisabled == 0 && !isSuper) {
|
||||
btnGroup.push({
|
||||
title: '编辑',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'update-employee'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.updataEmployee(params.row);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!isSuper) {
|
||||
let isDisableBtn;
|
||||
if (params.row.isDisabled == 0) {
|
||||
isDisableBtn = {
|
||||
title: '禁用',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'disabled-employee'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.updateEmployeeStatus(h, params);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
isDisableBtn = {
|
||||
title: '启用',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'disabled-employee'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.updateEmployeeStatus(h, params);
|
||||
}
|
||||
};
|
||||
}
|
||||
btnGroup.push(isDisableBtn);
|
||||
}
|
||||
if (!isSuper) {
|
||||
btnGroup.push({
|
||||
title: '密码重置',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'reset-employee-password'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.$Modal.confirm({
|
||||
title: '重置密码',
|
||||
content: '是否将密码重置为123456',
|
||||
onOk: () => {
|
||||
this.resetPassword(params.row.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
if (params.row.isDisabled == 1 && !isSuper) {
|
||||
btnGroup.push({
|
||||
title: '删除',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'delete-employee'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.$Modal.confirm({
|
||||
title: '删除',
|
||||
content: '确认删除?',
|
||||
onOk: () => {
|
||||
this.deleteEmployee(params.row.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
// return h('div', btnGroup)
|
||||
return this.$tableAction(h, btnGroup);
|
||||
}
|
||||
}
|
||||
],
|
||||
// 表格数据
|
||||
employeeTable: [],
|
||||
disableId: [],
|
||||
currentDisabled: 0,
|
||||
roleList: []
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {
|
||||
selectDepartment(newData) {
|
||||
this.selectDepartment = newData;
|
||||
this.pageNum = 1;
|
||||
this.getEmployeeList();
|
||||
}
|
||||
},
|
||||
filters: {},
|
||||
created() {},
|
||||
mounted() {
|
||||
this.getEmployeeList();
|
||||
},
|
||||
beforeCreate() {},
|
||||
beforeMount() {},
|
||||
beforeUpdate() {},
|
||||
updated() {},
|
||||
beforeDestroy() {},
|
||||
destroyed() {},
|
||||
activated() {},
|
||||
methods: {
|
||||
// 翻页
|
||||
changePage(pageNum) {
|
||||
this.pageNum = pageNum;
|
||||
this.getEmployeeList();
|
||||
},
|
||||
// 根据部门ID查询部门员工
|
||||
async getEmployeeList() {
|
||||
let param = {
|
||||
isDisabled: this.currentDisabled,
|
||||
pageSize: this.pageSize,
|
||||
pageNum: this.pageNum
|
||||
};
|
||||
param.departmentId = this.selectDepartment.id;
|
||||
try {
|
||||
this.isShowTablesLoading = true;
|
||||
param.keyword = this.searchEmployeeName;
|
||||
let result = await employeeApi.getEmployeeList(param);
|
||||
this.totalPage = result.data.total;
|
||||
this.employeeTable = result.data.list;
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
} finally {
|
||||
this.isShowTablesLoading = false;
|
||||
}
|
||||
},
|
||||
// 打开子组件的模态框
|
||||
showAddEmployeeModal() {
|
||||
this.$refs.employeeTableAdd.showModal();
|
||||
},
|
||||
// 根据是否启用查询成员
|
||||
queryEmployeeListByIsDisabled(type) {
|
||||
this.currentDisabled = type;
|
||||
this.pageNum = 1;
|
||||
this.getEmployeeList();
|
||||
},
|
||||
// 确定添加角色
|
||||
async confirmAddRole() {
|
||||
let roleList = this.employeeRole;
|
||||
try {
|
||||
this.isShowTablesLoading = true;
|
||||
let result = await employeeApi.updateRoles(
|
||||
Object.assign({
|
||||
employeeId: this.mid,
|
||||
roleIds: roleList
|
||||
})
|
||||
);
|
||||
this.isShowTablesLoading = false;
|
||||
this.$Message.success('授权成功');
|
||||
this.getEmployeeList();
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
this.isShowTablesLoading = false;
|
||||
}
|
||||
},
|
||||
// 确认添加角色的后台数据接口
|
||||
async getRoles(id) {
|
||||
try {
|
||||
this.isShowTablesLoading = true;
|
||||
let result = await roleApi.getRoles(id);
|
||||
this.isShowTablesLoading = false;
|
||||
this.roleList = result.data;
|
||||
this.employeeRole = [];
|
||||
this.roleList.forEach(item => {
|
||||
if (item.selected) {
|
||||
this.employeeRole.push(item.id);
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
this.isShowTablesLoading = false;
|
||||
}
|
||||
},
|
||||
// 点击打开员工角色选择框
|
||||
showManageRoleModal(h, param) {
|
||||
this.mid = param.row.id;
|
||||
this.isShowManageRoleModal = true;
|
||||
this.getRoles(param.row.id);
|
||||
},
|
||||
// 修改员工信息
|
||||
updataEmployee(detail) {
|
||||
if (this.departments[0].id == detail.departmentId) {
|
||||
detail.departmentName = this.departments[0].name;
|
||||
} else {
|
||||
this.departments[0].children.forEach(item => {
|
||||
if (item.id == detail.departmentId) {
|
||||
detail.departmentName = item.name;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (detail.birthday) {
|
||||
detail.birthday = utils.getDate(new Date(detail.birthday), 'YMD');
|
||||
}
|
||||
this.$refs.employeeTableAdd.showModal(detail);
|
||||
},
|
||||
// 点击搜索
|
||||
searchEmployees() {
|
||||
this.pageNum = 1;
|
||||
this.queryEmployeeListByIsDisabled(0);
|
||||
},
|
||||
// 表格左侧复选框,点击保存选中栏信息
|
||||
singleSelect(row) {
|
||||
this.disableId = row;
|
||||
},
|
||||
// 批量禁用
|
||||
GroupDisable(type) {
|
||||
if (this.disableId.length == 0) {
|
||||
this.$Message.error('请最少选择一项');
|
||||
return false;
|
||||
} else {
|
||||
this.currentDisabled = type;
|
||||
let disableIds = this.disableId.map(e => e.id);
|
||||
this.updateStatusBatch(
|
||||
Object.assign({ status: type, employeeIds: disableIds })
|
||||
);
|
||||
}
|
||||
},
|
||||
// 禁用/启用单个用户
|
||||
async updateEmployeeStatus(h, params) {
|
||||
try {
|
||||
this.isShowTablesLoading = true;
|
||||
let employeeId = params.row.id;
|
||||
let status = 0;
|
||||
if (params.row.isDisabled == 0) {
|
||||
status = 1;
|
||||
this.queryEmployeeListByIsDisabled(0);
|
||||
} else {
|
||||
status = 0;
|
||||
this.queryEmployeeListByIsDisabled(1);
|
||||
}
|
||||
let result = await employeeApi.updateStatus(employeeId, status);
|
||||
this.isShowTablesLoading = false;
|
||||
if (status) {
|
||||
this.$Message.success('禁用成功');
|
||||
this.getEmployeeList();
|
||||
} else {
|
||||
this.$Message.success('启用成功');
|
||||
this.queryEmployeeListByIsDisabled(1);
|
||||
}
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
this.isShowTablesLoading = false;
|
||||
}
|
||||
},
|
||||
// 批量禁用多个用户
|
||||
async updateStatusBatch(param) {
|
||||
try {
|
||||
this.isShowTablesLoading = true;
|
||||
let result = await employeeApi.updateStatusBatch(param);
|
||||
this.isShowTablesLoading = false;
|
||||
this.$Message.success('操作成功');
|
||||
this.disableId = [];
|
||||
this.queryEmployeeListByIsDisabled(this.currentDisabled);
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
this.isShowTablesLoading = false;
|
||||
}
|
||||
},
|
||||
// 重置密码
|
||||
async resetPassword(id) {
|
||||
try {
|
||||
this.isShowTablesLoading = true;
|
||||
let result = await employeeApi.resetPassword(id);
|
||||
this.isShowTablesLoading = false;
|
||||
this.$Message.success('操作成功');
|
||||
|
||||
this.queryEmployeeListByIsDisabled(this.currentDisabled);
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
this.isShowTablesLoading = false;
|
||||
}
|
||||
},
|
||||
// 删除成员
|
||||
async deleteEmployee(id) {
|
||||
try {
|
||||
this.isShowTablesLoading = true;
|
||||
let result = await employeeApi.deleteEmployee(id);
|
||||
this.isShowTablesLoading = false;
|
||||
this.$Message.success('操作成功');
|
||||
this.queryEmployeeListByIsDisabled(this.currentDisabled);
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
this.isShowTablesLoading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ivu-tree-children {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.option-department {
|
||||
font-size: 14px;
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.searchable-table-con1 {
|
||||
min-height: 350px !important;
|
||||
}
|
||||
|
||||
.option-department:hover {
|
||||
background-color: rgba(5, 170, 250, 0.2);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,831 @@
|
||||
<template>
|
||||
<div>
|
||||
<!--Row 员工管理 start-->
|
||||
<Row :gutter="10">
|
||||
<!--Col 左侧公司组织列表 start-->
|
||||
<Col :lg="5" :md="8">
|
||||
<Card class="warp-card" dis-hover>
|
||||
<p slot="title">公司组织</p>
|
||||
<Row>
|
||||
<Input
|
||||
@on-change="getListEmployeeByDepartmentName"
|
||||
placeholder="输入部门名称"
|
||||
v-model="departmentName"
|
||||
/>
|
||||
</Row>
|
||||
<Tree
|
||||
:data="departmentGroup"
|
||||
:render="renderDepartmentTreeButton"
|
||||
style="height: 485px;overflow-x: scroll"
|
||||
></Tree>
|
||||
</Card>
|
||||
</Col>
|
||||
<!--Col 左侧公司组织列表 end-->
|
||||
<!--EmployeeTable 表单列表模块 start-->
|
||||
<EmployeeTable :departments="departmentGroup" :selectDepartment="selectDepartment"></EmployeeTable>
|
||||
<!--EmployeeTable 表单列表模块 end-->
|
||||
<!--Modal 添加部门弹窗 start-->
|
||||
<Modal
|
||||
@on-visible-change="changeVisibleOperationModal"
|
||||
title="添加部门"
|
||||
v-model="isShowOperationModal"
|
||||
>
|
||||
<Form :label-width="80">
|
||||
<FormItem label="名称" required>
|
||||
<Input
|
||||
@on-keydown="departmentParam.name=departmentParam.name.replace(/^ +| +$/g,'')"
|
||||
@on-keyup="departmentParam.name=departmentParam.name.replace(/^ +| +$/g,'')"
|
||||
v-model="departmentParam.name"
|
||||
></Input>
|
||||
</FormItem>
|
||||
<FormItem class="selectClass" label="负责人">
|
||||
<Input
|
||||
@click.native="showTree"
|
||||
placeholder="请选择负责人"
|
||||
readonly
|
||||
v-model="departmentParam.managerName"
|
||||
>
|
||||
<Icon slot="suffix" type="ios-arrow-down" v-if="!isShowTree" />
|
||||
<Icon slot="suffix" type="ios-arrow-up" v-else />
|
||||
</Input>
|
||||
<div class="departmentWrap">
|
||||
<DepartmentEmployeeTree
|
||||
:selectEmployeeId="selectEmployeeId"
|
||||
@on-select="selectDepartmentEmployee"
|
||||
ref="departmentEmployeeTree"
|
||||
></DepartmentEmployeeTree>
|
||||
</div>
|
||||
</FormItem>
|
||||
<FormItem label="上级部门" required>
|
||||
<Input disabled v-model="departmentParam.parentName" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer">
|
||||
<Button @click="getOperationDepartmentData()" size="large" type="primary">确定</Button>
|
||||
<Button @click="hideDeleteAndOperationModal" size="large" type="error">取消</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
<!--Modal 添加部门弹窗 end-->
|
||||
<!--Modal 删除部门弹窗 start-->
|
||||
<Modal title="删除确认" v-model="isShowDeleteModal">
|
||||
<p style="font-size: 16px;">
|
||||
确定要将
|
||||
<span style="color: red;font-size: 16px;">{{departmentParam.name}}</span>
|
||||
部门删除吗?
|
||||
</p>
|
||||
<div slot="footer">
|
||||
<Button @click="deleteDepartment" size="large" type="primary">确定</Button>
|
||||
<Button @click="hideDeleteAndOperationModal" size="large" type="error">取消</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
<!--Modal 删除部门弹窗 end-->
|
||||
<!--Modal 公司设置弹窗 start-->
|
||||
<Modal title="公司设置" v-model="isShowCompanySettingModal">
|
||||
<Form :label-width="80">
|
||||
<FormItem label="公司名称" required>
|
||||
<Input
|
||||
:disabled=" departmentParam.id!=null"
|
||||
@on-keydown="departmentParam.name=departmentParam.name.replace(/^ +| +$/g,'')"
|
||||
@on-keyup="departmentParam.name=departmentParam.name.replace(/^ +| +$/g,'')"
|
||||
v-model="departmentParam.name"
|
||||
/>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer">
|
||||
<Button
|
||||
@click="getOperationDepartmentData()"
|
||||
size="large"
|
||||
type="primary"
|
||||
v-if=" !departmentParam.id"
|
||||
>确定</Button>
|
||||
<Button @click="hideCompanySettingModal" size="large" type="error">取消</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
<!--Modal 公司设置弹窗 end-->
|
||||
</Row>
|
||||
<!--Row 员工管理 end-->
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import $ from 'jquery';
|
||||
import { departmentApi } from '@/api/department';
|
||||
import EmployeeTable from './components/employee-table/employee-table';
|
||||
import DepartmentEmployeeTree from '../components/department-employee-tree/department-employee-tree';
|
||||
export default {
|
||||
name: 'RoleEmployeeManage',
|
||||
components: {
|
||||
EmployeeTable,
|
||||
DepartmentEmployeeTree
|
||||
},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
departmentName: '',
|
||||
isShowTree: false,
|
||||
// 选中的部门
|
||||
selectDepartment: {},
|
||||
isShowOperationModal: false,
|
||||
isShowDeleteModal: false,
|
||||
// 部门参数
|
||||
departmentParam: {
|
||||
id: '',
|
||||
name: '',
|
||||
managerId: null,
|
||||
managerName: '',
|
||||
parentName: '',
|
||||
parentId: '',
|
||||
type: 1
|
||||
},
|
||||
selectEmployeeId: null,
|
||||
// 备用的部门参数
|
||||
departmentParamBackup: {},
|
||||
isShowCompanySettingModal: false,
|
||||
// 员工table 表格样式功能
|
||||
departmentGroup: [
|
||||
{
|
||||
name: '',
|
||||
expand: true,
|
||||
render: (h, { root, node, data }) => {
|
||||
let newName = data.name;
|
||||
if (newName.length > 8) {
|
||||
newName = data.name.substring(0, 8) + '...';
|
||||
}
|
||||
if (!data || Object.keys(data).length === 0 || !data.id) {
|
||||
return h('span', '');
|
||||
}
|
||||
return h(
|
||||
'Tooltip',
|
||||
{
|
||||
props: {
|
||||
placement: 'right'
|
||||
},
|
||||
style: { fontSize: '12px' }
|
||||
},
|
||||
[
|
||||
h(
|
||||
'span',
|
||||
{
|
||||
style: {
|
||||
display: 'inline-block'
|
||||
}
|
||||
},
|
||||
[
|
||||
h('span', [
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
props: {
|
||||
// content:'123',
|
||||
// placement: 'top'
|
||||
},
|
||||
style: { fontSize: '12px' }
|
||||
},
|
||||
[
|
||||
h('Icon', {
|
||||
props: {
|
||||
type: 'md-cube'
|
||||
},
|
||||
style: {
|
||||
marginRight: '8px'
|
||||
}
|
||||
}),
|
||||
h(
|
||||
'Button',
|
||||
{
|
||||
props: Object.assign({}),
|
||||
class: ['departmentSelect'],
|
||||
style: {
|
||||
border: 'none',
|
||||
background: '#ffffff',
|
||||
padding: '4px 5px'
|
||||
},
|
||||
on: {
|
||||
click: event => {
|
||||
this.loadEmployeeTable(
|
||||
event,
|
||||
root,
|
||||
node,
|
||||
data
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
newName
|
||||
)
|
||||
]
|
||||
)
|
||||
])
|
||||
]
|
||||
),
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
slot: 'content'
|
||||
},
|
||||
[
|
||||
h(
|
||||
'a',
|
||||
{
|
||||
props: {},
|
||||
style: {
|
||||
color: '#fff',
|
||||
margin: '0 5px 5px'
|
||||
},
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'addDepartment'
|
||||
}
|
||||
],
|
||||
on: {
|
||||
click: () => {
|
||||
this.addOrUpdataDepartment(data, false);
|
||||
}
|
||||
}
|
||||
},
|
||||
'添加'
|
||||
)
|
||||
]
|
||||
),
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
slot: 'content'
|
||||
},
|
||||
[
|
||||
h(
|
||||
'a',
|
||||
{
|
||||
props: {},
|
||||
style: {
|
||||
color: '#fff',
|
||||
margin: '0 5px 5px'
|
||||
},
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'update-department'
|
||||
}
|
||||
],
|
||||
on: {
|
||||
click: () => {
|
||||
data.parentId = 0;
|
||||
this.addOrUpdataDepartment(data, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
'编辑'
|
||||
)
|
||||
]
|
||||
)
|
||||
]
|
||||
);
|
||||
},
|
||||
children: []
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
filters: {},
|
||||
created() {},
|
||||
mounted() {
|
||||
Object.assign(this.departmentParamBackup, this.departmentParam);
|
||||
this.getListEmployeeByDepartmentName();
|
||||
let self = this;
|
||||
$('.selectClass').click(event => {
|
||||
event = event || window.event;
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// 点击层外,隐藏这个层。由于层内的事件停止了冒泡,所以不会触发这个事件
|
||||
$(document).click(function(e) {
|
||||
self.isShowTree = false;
|
||||
$('.departmentWrap').hide();
|
||||
});
|
||||
},
|
||||
beforeCreate() {},
|
||||
beforeMount() {},
|
||||
beforeUpdate() {},
|
||||
updated() {},
|
||||
beforeDestroy() {},
|
||||
destroyed() {},
|
||||
activated() {},
|
||||
methods: {
|
||||
// 初始化加载数据
|
||||
async getListEmployeeByDepartmentName() {
|
||||
this.$Spin.show();
|
||||
let result = await departmentApi.getListEmployeeByDepartmentName(
|
||||
this.departmentName
|
||||
);
|
||||
this.$Spin.hide();
|
||||
let data = result.data;
|
||||
this.departmentGroup[0].id = null;
|
||||
this.departmentGroup[0].name = '';
|
||||
this.departmentGroup[0].children = [];
|
||||
this.departmentGroup[0].organizationId = [];
|
||||
this.departmentGroup[0].organizationName = [];
|
||||
this.departmentGroup[0].type = 1;
|
||||
if (data && data[0]) {
|
||||
let dateFirst = data[0];
|
||||
this.departmentGroup[0].id = dateFirst.id;
|
||||
this.departmentGroup[0].name = dateFirst.name;
|
||||
this.departmentGroup[0].children = dateFirst.children;
|
||||
this.departmentGroup[0].organizationId = dateFirst.organizationId;
|
||||
this.departmentGroup[0].organizationName = dateFirst.organizationName;
|
||||
this.departmentGroup[0].type = dateFirst.type;
|
||||
}
|
||||
},
|
||||
// 渲染部门树形图功能按钮
|
||||
renderDepartmentTreeButton(h, { root, node, data }) {
|
||||
let newName = data.name;
|
||||
if (newName.length > 8) {
|
||||
newName = data.name.substring(0, 8) + '...';
|
||||
}
|
||||
let icon = '';
|
||||
if (data.type === 1) {
|
||||
icon = 'md-cube';
|
||||
} else {
|
||||
icon = 'md-menu';
|
||||
}
|
||||
let buttonList = [
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
margin: '0 5px 5px 5px'
|
||||
}
|
||||
},
|
||||
[
|
||||
h(
|
||||
'a',
|
||||
{
|
||||
props: {},
|
||||
style: {
|
||||
color: '#fff',
|
||||
margin: '0 5px 5px'
|
||||
},
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'update-department'
|
||||
}
|
||||
],
|
||||
on: {
|
||||
click: () => {
|
||||
this.addOrUpdataDepartment(data, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
'编辑'
|
||||
)
|
||||
]
|
||||
),
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
margin: '0 5px 5px 5px'
|
||||
}
|
||||
},
|
||||
[
|
||||
h(
|
||||
'a',
|
||||
{
|
||||
props: {},
|
||||
style: {
|
||||
color: '#fff',
|
||||
margin: '0 5px 5px'
|
||||
},
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'add-department'
|
||||
}
|
||||
],
|
||||
on: {
|
||||
click: () => {
|
||||
this.addOrUpdataDepartment(data, false);
|
||||
}
|
||||
}
|
||||
},
|
||||
'添加'
|
||||
)
|
||||
]
|
||||
),
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
margin: '0 5px 5px 5px'
|
||||
}
|
||||
},
|
||||
[
|
||||
h(
|
||||
'a',
|
||||
{
|
||||
props: {},
|
||||
style: {
|
||||
color: '#fff',
|
||||
margin: '0 5px 5px'
|
||||
},
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'delete-department'
|
||||
}
|
||||
],
|
||||
on: {
|
||||
click: () => {
|
||||
this.showDeleteModal(data);
|
||||
}
|
||||
}
|
||||
},
|
||||
'删除'
|
||||
)
|
||||
]
|
||||
)
|
||||
];
|
||||
|
||||
if (data.preId) {
|
||||
buttonList.push(
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
margin: '0 5px 5px 5px'
|
||||
}
|
||||
},
|
||||
[
|
||||
h(
|
||||
'a',
|
||||
{
|
||||
props: {},
|
||||
style: {
|
||||
color: '#fff',
|
||||
margin: '0 5px 5px'
|
||||
},
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'delete-department'
|
||||
}
|
||||
],
|
||||
on: {
|
||||
click: () => {
|
||||
this.upOrDownDepartment(data.id, data.preId);
|
||||
}
|
||||
}
|
||||
},
|
||||
'上移'
|
||||
)
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
if (data.nextId) {
|
||||
buttonList.push(
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
margin: '0 5px 5px 5px'
|
||||
}
|
||||
},
|
||||
[
|
||||
h(
|
||||
'a',
|
||||
{
|
||||
props: {},
|
||||
style: {
|
||||
color: '#fff',
|
||||
margin: '0 5px 5px'
|
||||
},
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'delete-department'
|
||||
}
|
||||
],
|
||||
on: {
|
||||
click: () => {
|
||||
this.upOrDownDepartment(data.id, data.nextId);
|
||||
}
|
||||
}
|
||||
},
|
||||
'下移'
|
||||
)
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
if (data.parentId && data.parentId !== 1) {
|
||||
buttonList.push(
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
margin: '0 5px 5px 5px'
|
||||
}
|
||||
},
|
||||
[
|
||||
h(
|
||||
'a',
|
||||
{
|
||||
props: {},
|
||||
style: {
|
||||
color: '#fff',
|
||||
margin: '0 5px 5px'
|
||||
},
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'delete-department'
|
||||
}
|
||||
],
|
||||
on: {
|
||||
click: () => {
|
||||
this.upDepartmentGrade(data.id);
|
||||
}
|
||||
}
|
||||
},
|
||||
'升级'
|
||||
)
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (data.preId) {
|
||||
buttonList.push(
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
margin: '0 5px 5px 5px'
|
||||
}
|
||||
},
|
||||
[
|
||||
h(
|
||||
'a',
|
||||
{
|
||||
props: {},
|
||||
style: {
|
||||
color: '#fff',
|
||||
margin: '0 5px 5px'
|
||||
},
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'delete-department'
|
||||
}
|
||||
],
|
||||
on: {
|
||||
click: () => {
|
||||
this.downDepartmentGrade(data.id, data.preId);
|
||||
}
|
||||
}
|
||||
},
|
||||
'降级'
|
||||
)
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
return h(
|
||||
'Tooltip',
|
||||
{
|
||||
props: {
|
||||
placement: 'right'
|
||||
},
|
||||
style: { fontSize: '12px' }
|
||||
},
|
||||
[
|
||||
h(
|
||||
'span',
|
||||
{
|
||||
style: {
|
||||
display: 'inline-block'
|
||||
}
|
||||
},
|
||||
[
|
||||
h('span', [
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
props: {
|
||||
// content:'123',
|
||||
// placement: 'top'
|
||||
},
|
||||
style: { fontSize: '12px' }
|
||||
},
|
||||
[
|
||||
h('Icon', {
|
||||
props: {
|
||||
type: icon
|
||||
},
|
||||
style: {
|
||||
marginRight: '8px'
|
||||
}
|
||||
}),
|
||||
h(
|
||||
'Button',
|
||||
{
|
||||
props: Object.assign({}),
|
||||
class: ['departmentSelect'],
|
||||
style: {
|
||||
border: 'none',
|
||||
background: '#ffffff',
|
||||
padding: '4px 5px'
|
||||
},
|
||||
on: {
|
||||
click: event => {
|
||||
console.log('11');
|
||||
this.loadEmployeeTable(event, root, node, data);
|
||||
}
|
||||
}
|
||||
},
|
||||
newName
|
||||
)
|
||||
]
|
||||
)
|
||||
])
|
||||
]
|
||||
),
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
slot: 'content'
|
||||
},
|
||||
buttonList
|
||||
)
|
||||
]
|
||||
);
|
||||
},
|
||||
// 选中部门 更新员工table
|
||||
loadEmployeeTable(event, root, node, data) {
|
||||
$('.departmentSelect').css({ background: '#ffffff', color: 'black' });
|
||||
let target = event.target;
|
||||
let tagName = target.tagName;
|
||||
if (tagName !== 'BUTTON') {
|
||||
target.parentNode.style.backgroundColor = '#5cadff';
|
||||
target.parentNode.style.color = '#ffffff';
|
||||
} else {
|
||||
target.style.backgroundColor = '#5cadff';
|
||||
target.style.color = '#ffffff';
|
||||
}
|
||||
this.selectDepartment = data;
|
||||
},
|
||||
// 关闭模态框
|
||||
hideDeleteAndOperationModal() {
|
||||
this.isShowDeleteModal = false;
|
||||
this.isShowOperationModal = false;
|
||||
},
|
||||
// 隐藏公司设置弹窗
|
||||
hideCompanySettingModal() {
|
||||
this.isShowCompanySettingModal = false;
|
||||
},
|
||||
// 获取部门数据
|
||||
async getOperationDepartmentData() {
|
||||
if (!this.departmentParam.name) {
|
||||
this.$Message.error('名称不能为空');
|
||||
return;
|
||||
}
|
||||
this.$Spin.show();
|
||||
let result;
|
||||
if (this.departmentParam.id) {
|
||||
result = await departmentApi.updateDepartment(this.departmentParam);
|
||||
} else {
|
||||
result = await departmentApi.addDepartment(this.departmentParam);
|
||||
}
|
||||
this.$Spin.hide();
|
||||
this.$Message.success('操作成功');
|
||||
this.getListEmployeeByDepartmentName();
|
||||
this.hideDeleteAndOperationModal();
|
||||
this.hideCompanySettingModal();
|
||||
},
|
||||
// 删除部门
|
||||
async deleteDepartment() {
|
||||
this.$Spin.show();
|
||||
let result = await departmentApi.deleteDepartment(
|
||||
this.departmentParam.id
|
||||
);
|
||||
this.$Message.success('删除成功');
|
||||
this.$Spin.hide();
|
||||
this.getListEmployeeByDepartmentName();
|
||||
this.hideDeleteModal();
|
||||
},
|
||||
// 添加或编辑部门 并显示弹窗
|
||||
addOrUpdataDepartment(data, update) {
|
||||
this.selectEmployeeId = null;
|
||||
if (update) {
|
||||
this.departmentParam = Object.assign({}, data);
|
||||
this.selectEmployeeId = data.managerId;
|
||||
} else {
|
||||
this.departmentParam = {
|
||||
parentName: data.name,
|
||||
parentId: data.id,
|
||||
type: 1
|
||||
};
|
||||
}
|
||||
this.isShowOperationModal = true;
|
||||
},
|
||||
// 显示删除弹窗
|
||||
showDeleteModal(val) {
|
||||
let data;
|
||||
if (!val) {
|
||||
data = Object.assign({}, this.departmentGroup[0]);
|
||||
} else {
|
||||
data = Object.assign({}, val);
|
||||
}
|
||||
this.departmentParam = {
|
||||
id: data.id,
|
||||
name: data.name
|
||||
};
|
||||
this.isShowDeleteModal = true;
|
||||
},
|
||||
// 关闭删除弹窗
|
||||
hideDeleteModal() {
|
||||
this.departmentParam = Object.assign({}, this.departmentParamBackup);
|
||||
this.isShowDeleteModal = false;
|
||||
},
|
||||
// 部门树形图的显示与隐藏
|
||||
showTree() {
|
||||
if (this.isShowTree) {
|
||||
this.isShowTree = false;
|
||||
$('.departmentWrap').hide();
|
||||
} else {
|
||||
this.isShowTree = true;
|
||||
$('.departmentWrap').show();
|
||||
this.$refs.departmentEmployeeTree.resetSearch();
|
||||
}
|
||||
},
|
||||
// 选中树形一项
|
||||
selectDepartmentEmployee(emp) {
|
||||
this.$set(this.departmentParam, 'managerId', emp.id);
|
||||
this.$set(this.departmentParam, 'managerName', emp.name);
|
||||
this.isShowTree = false;
|
||||
$('.departmentWrap').hide();
|
||||
},
|
||||
// 添加部门弹窗 显示隐藏监听
|
||||
changeVisibleOperationModal(showStatus) {
|
||||
if (!showStatus) {
|
||||
this.isShowTree = false;
|
||||
$('.departmentWrap').hide();
|
||||
this.$refs.departmentEmployeeTree.generateTreeData();
|
||||
}
|
||||
},
|
||||
// 部门上移或者下移
|
||||
async upOrDownDepartment(departmentId, swapId) {
|
||||
this.$Spin.show();
|
||||
let result = await departmentApi.upOrDown(departmentId, swapId);
|
||||
this.$Spin.hide();
|
||||
this.$Message.success('操作成功');
|
||||
this.getListEmployeeByDepartmentName();
|
||||
},
|
||||
// 升级
|
||||
async upDepartmentGrade(departmentId) {
|
||||
this.$Spin.show();
|
||||
let result = await departmentApi.upGrade(departmentId);
|
||||
this.$Message.success('升级成功');
|
||||
this.$Spin.hide();
|
||||
this.getListEmployeeByDepartmentName();
|
||||
},
|
||||
// 降级
|
||||
async downDepartmentGrade(departmentId, preId) {
|
||||
this.$Spin.show();
|
||||
let result = await departmentApi.downGrade(departmentId, preId);
|
||||
this.$Message.success('降级成功');
|
||||
this.$Spin.hide();
|
||||
this.getListEmployeeByDepartmentName();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.ivu-tree-children {
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
}
|
||||
.option-department {
|
||||
font-size: 14px;
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.option-department:hover {
|
||||
background-color: rgba(5, 170, 250, 0.2);
|
||||
}
|
||||
.departmentWrap {
|
||||
position: absolute;
|
||||
background-color: #ffffff;
|
||||
padding: 5px;
|
||||
border: 1px solid #dedede;
|
||||
width: 100%;
|
||||
z-index: 9;
|
||||
display: none;
|
||||
height: 250px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<!--div tab切换,数据范围部分 start-->
|
||||
<div>
|
||||
<Row>
|
||||
<Col span="16" style="margin:20px 0;font-size: 15px;color: #95a5a6;"></Col>
|
||||
<Col class="button-style" span="8">
|
||||
<Button
|
||||
@click.native="updateDataScope"
|
||||
style="margin-right: 20px;"
|
||||
type="primary"
|
||||
v-privilege="'update-data-scope'"
|
||||
>保存</Button>
|
||||
<Button @click.native="getDataScope()" type="warning" v-privilege="'query-data-scope'">刷新</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style="border-bottom: 1px solid #f2f2f2;font-weight: 600; margin: 10px 0px;">
|
||||
<Col class="tab-margin" span="4">业务单据</Col>
|
||||
<Col class="tab-data" span="6">查看数据范围</Col>
|
||||
<Col class="tab-margin" span="14"></Col>
|
||||
</Row>
|
||||
<div class="no-scrollbar" style="height:680px;overflow-y: scroll">
|
||||
<Row
|
||||
:key="item.dataScopeType "
|
||||
style="border-bottom: 1px solid #f2f2f2; margin: 10px 0px;"
|
||||
v-for="item in this.dataScopeList"
|
||||
>
|
||||
<Col span="4" style="line-height:100px; text-align: center">{{item.dataScopeTypeName}}</Col>
|
||||
<!--Col 数据范围选中 start-->
|
||||
<Col class="tab-data" span="6">
|
||||
<RadioGroup v-model="item.viewType" vertical>
|
||||
<Radio
|
||||
:key="index+'viewType'"
|
||||
:label="scope.viewType"
|
||||
v-for="(scope,index) in item.viewTypeList"
|
||||
>{{scope.viewTypeName }}</Radio>
|
||||
</RadioGroup>
|
||||
</Col>
|
||||
<!--Col 数据范围选中 end-->
|
||||
<Col span="14" style="text-indent:2rem;line-height:30px;font-size:16px;color: #a3a3a3;">
|
||||
<p style="padding: 30px 0;">{{item.dataScopeTypeDesc}}</p>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</div>
|
||||
<!--div tab切换,数据范围部分 end-->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { dataScopeApi } from '@/api/data-scope';
|
||||
export default {
|
||||
name: 'RoleDataScope',
|
||||
components: {},
|
||||
props: {
|
||||
// 角色id
|
||||
roleId: {
|
||||
type: Number,
|
||||
required: true,
|
||||
validator: value => {
|
||||
return value >= 0;
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dataScopeList: {}
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
filters: {},
|
||||
created() {},
|
||||
mounted() {
|
||||
this.getDataScope();
|
||||
},
|
||||
beforeCreate() {},
|
||||
beforeMount() {},
|
||||
beforeUpdate() {},
|
||||
updated() {},
|
||||
beforeDestroy() {},
|
||||
destroyed() {},
|
||||
activated() {},
|
||||
methods: {
|
||||
// 更新
|
||||
async updateDataScope() {
|
||||
try {
|
||||
let data = {
|
||||
roleId: this.roleId,
|
||||
batchSetList: this.dataScopeList
|
||||
};
|
||||
await dataScopeApi.updateDataScope(data);
|
||||
this.$Message.success('保存成功');
|
||||
this.getDataScope(this.employeeId);
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
}
|
||||
},
|
||||
// 获取数据
|
||||
async getDataScope() {
|
||||
try {
|
||||
let result = await dataScopeApi.getDataScopeList();
|
||||
this.dataScopeList = result.data;
|
||||
this.getRoleDataScope();
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
}
|
||||
},
|
||||
// 获取数据范围根据角色id
|
||||
async getRoleDataScope() {
|
||||
try {
|
||||
let result = await dataScopeApi.getDataScopeByRoleId(this.roleId);
|
||||
let data = result.data;
|
||||
this.dataScopeList.forEach((item, i) => {
|
||||
let find = data.find(e => e.dataScopeType == item.dataScopeType);
|
||||
if (find) {
|
||||
this.$set(item, 'viewType', find.viewType);
|
||||
} else {
|
||||
this.$set(item, 'viewType', '');
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.button-style {
|
||||
margin: 20px 0 20px 0;
|
||||
padding-left: 20px;
|
||||
text-align: right;
|
||||
}
|
||||
.tab-data {
|
||||
padding-left: 30px;
|
||||
margin: 10px 0px;
|
||||
}
|
||||
.tab-margin {
|
||||
text-align: center;
|
||||
margin: 10px 0px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,407 @@
|
||||
<template>
|
||||
<!--div tab切换成员列表部分 start-->
|
||||
<div>
|
||||
<Row>
|
||||
<Col span="16" style="margin:20px 0;font-size: 15px;color: #95a5a6;">管理拥有当前角色权限的人员列表</Col>
|
||||
<Col span="8" style="margin:20px 0; text-align: right;">
|
||||
<Button
|
||||
@click="addEmployee"
|
||||
type="primary"
|
||||
v-privilege="'add-employee-role'"
|
||||
>添加成员</Button>
|
||||
|
||||
<Button
|
||||
@click="deleteEmployees()"
|
||||
style="margin-left:10px"
|
||||
type="error"
|
||||
v-privilege="'delete-employee-role-batch'"
|
||||
>批量移除</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
<!--Table 表格列表 start-->
|
||||
<Table
|
||||
:columns="columns"
|
||||
:data="tableData"
|
||||
:loading="isShowTablesLoading"
|
||||
@on-selection-change="selectChange"
|
||||
border
|
||||
ref="selection"
|
||||
></Table>
|
||||
<!--Table 表格列表 end-->
|
||||
<Row class="page" justify="end" type="flex">
|
||||
<Col order="2" span="24" style="text-align: right;margin-top:20px;">
|
||||
<Page
|
||||
:current="currentPage"
|
||||
:page-size="pageSize"
|
||||
:total="total"
|
||||
@on-change="changePage"
|
||||
show-elevator
|
||||
></Page>
|
||||
</Col>
|
||||
</Row>
|
||||
<!--modal 添加成员 start-->
|
||||
<Modal
|
||||
@on-ok="confirmPrepAddEmployees()"
|
||||
style="min-width:1800px"
|
||||
title="添加成员"
|
||||
v-model="isShowEmployeeModal"
|
||||
width="700"
|
||||
>
|
||||
<Row class="shuttle-box">
|
||||
<!--Col 左侧员工列表 start-->
|
||||
<Col class="box" span="11">
|
||||
<Row>
|
||||
<Col class="title" span="24">员工列表</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col
|
||||
@dblclick.native="getCharge"
|
||||
class="no-scrollbar"
|
||||
id="goRight"
|
||||
span="24"
|
||||
style="height: 290px;overflow-y:scroll"
|
||||
>
|
||||
<DepartmentEmployeeTree ref="departmentEmployeeTree"></DepartmentEmployeeTree>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
<!--Col 左侧员工列表 end-->
|
||||
<!--Col 转移按钮 start-->
|
||||
<Col span="2" style="text-align: center;">
|
||||
<Icon
|
||||
@click.native="addPrepEmployees"
|
||||
size="30"
|
||||
style="line-height: 350px"
|
||||
type="md-arrow-round-forward"
|
||||
></Icon>
|
||||
</Col>
|
||||
<!--Col 转移按钮 end-->
|
||||
<!--Col 右侧预添加列表 start-->
|
||||
<Col class="box" span="11">
|
||||
<Row>
|
||||
<Col class="title" span="24">成员列表</Col>
|
||||
<Col
|
||||
class="no-scrollbar"
|
||||
span="24"
|
||||
style="overflow-y:scroll;height: 290px;text-align: center"
|
||||
>
|
||||
<Row :key="index" v-for="(item,index) in prepAddEmployees">
|
||||
<Col span="24" style="font-size: 15px;text-align: center;">
|
||||
<icon type="ios-people"></icon>
|
||||
{{item.manageName}}
|
||||
<Button @click.native="deletePrepEmployee(index)" icon="md-close" type="text"></Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
<!--Col 右侧预添加列表 end-->
|
||||
</Row>
|
||||
</Modal>
|
||||
<!--modal 添加成员 end-->
|
||||
</div>
|
||||
<!--div tab切换成员列表部分 end-->
|
||||
</template>
|
||||
<script>
|
||||
import DepartmentEmployeeTree from '../../../components/department-employee-tree/department-employee-tree';
|
||||
import { roleApi } from '@/api/role';
|
||||
|
||||
export default {
|
||||
name: 'RoleList',
|
||||
components: {
|
||||
DepartmentEmployeeTree
|
||||
},
|
||||
props: {
|
||||
// 角色id
|
||||
roleId: {
|
||||
type: Number,
|
||||
required: true,
|
||||
validator: value => {
|
||||
return value >= 0;
|
||||
}
|
||||
}
|
||||
},
|
||||
// 数据
|
||||
data() {
|
||||
return {
|
||||
// 是否显示添加成员弹窗
|
||||
isShowEmployeeModal: false,
|
||||
currentPage: 1,
|
||||
isShowTablesLoading: false,
|
||||
columns: [
|
||||
{
|
||||
type: 'selection',
|
||||
width: 60,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '登录名',
|
||||
key: 'loginName'
|
||||
},
|
||||
{
|
||||
title: '姓名',
|
||||
key: 'actualName'
|
||||
},
|
||||
{
|
||||
title: '手机号',
|
||||
key: 'phone'
|
||||
},
|
||||
{
|
||||
title: '邮箱',
|
||||
key: 'email'
|
||||
},
|
||||
{
|
||||
title: '部门',
|
||||
key: 'departmentName'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'operation ',
|
||||
width: 100,
|
||||
align: 'center',
|
||||
className: 'action-hide',
|
||||
render: (h, params) => {
|
||||
return this.$tableAction(h, [
|
||||
{
|
||||
title: '移除',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'delete-employee-role'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.deleteEmployee(params.index);
|
||||
}
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
],
|
||||
employeeData: {
|
||||
// orderby:'',
|
||||
roleId: '',
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
sort: ''
|
||||
},
|
||||
// 表格数据
|
||||
tableData: [],
|
||||
// 待添加的成员列表
|
||||
prepAddEmployees: [],
|
||||
// 提交添加成员数据
|
||||
submitPrepAddEmployeesData: {
|
||||
// 提交成员id列表
|
||||
employeeIds: [],
|
||||
// 当前roleId
|
||||
roleId: 0
|
||||
},
|
||||
// 批量删除的id列表
|
||||
deleteIds: [],
|
||||
total: 0,
|
||||
pageSize: 0
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {
|
||||
roleId(val) {
|
||||
if (val) {
|
||||
this.employeeData.roleId = this.roleId;
|
||||
this.getListEmployee(this.employeeData);
|
||||
}
|
||||
}
|
||||
},
|
||||
filters: {},
|
||||
created() {},
|
||||
mounted() {
|
||||
this.employeeData.roleId = this.roleId;
|
||||
this.getListEmployee(this.employeeData);
|
||||
},
|
||||
beforeCreate() {},
|
||||
beforeMount() {},
|
||||
beforeUpdate() {},
|
||||
updated() {},
|
||||
beforeDestroy() {},
|
||||
destroyed() {},
|
||||
activated() {},
|
||||
methods: {
|
||||
// 批量删除
|
||||
deleteEmployees() {
|
||||
let object = {};
|
||||
object.employeeIds = this.deleteIds.slice(0, this.deleteIds.length);
|
||||
object.roleId = this.roleId;
|
||||
if (object.employeeIds.length <= 0) {
|
||||
this.$Message.error('请先选择要移除的成员');
|
||||
} else {
|
||||
this.deleteEmployeeList(object); // 删除
|
||||
}
|
||||
},
|
||||
// 删除待添加列表中 人员
|
||||
deletePrepEmployee(index) {
|
||||
this.prepAddEmployees.splice(index, 1);
|
||||
},
|
||||
// 批量删除方法
|
||||
async deleteEmployeeList(param) {
|
||||
this.isShowTablesLoading = true;
|
||||
try {
|
||||
await roleApi.deleteEmployeeList(param);
|
||||
await this.getListEmployee(this.employeeData); // 刷新数据
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
} finally {
|
||||
this.isShowTablesLoading = false;
|
||||
}
|
||||
},
|
||||
// 选项框多选移除
|
||||
selectChange(selection) {
|
||||
this.deleteIds = [];
|
||||
for (let i = 0; i < selection.length; i++) {
|
||||
this.deleteIds.push(selection[i].id);
|
||||
}
|
||||
console.log(this.deleteIds);
|
||||
},
|
||||
// 移除当前项
|
||||
deleteEmployee(index) {
|
||||
let object = {};
|
||||
object.employeeId = this.tableData[index].id;
|
||||
object.roleId = this.roleId;
|
||||
this.deleteEmployeeRole(object);
|
||||
},
|
||||
// 删除角色成员方法
|
||||
async deleteEmployeeRole(param) {
|
||||
this.isShowTablesLoading = true;
|
||||
try {
|
||||
await roleApi.deleteEmployeeRole(param);
|
||||
this.$Message.success('移除成功');
|
||||
await this.getListEmployee(this.employeeData);
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
} finally {
|
||||
this.isShowTablesLoading = false;
|
||||
}
|
||||
},
|
||||
// 分页改变获取数据方法
|
||||
// 分页器
|
||||
changePage(number) {
|
||||
console.log(number);
|
||||
let object = {};
|
||||
object.roleId = this.roleId;
|
||||
this.currentPage = number;
|
||||
object.pageNum = number;
|
||||
object.pageSize = this.pageSize;
|
||||
object.sort = '';
|
||||
this.getListEmployee(object);
|
||||
},
|
||||
// 确定添加角色成员
|
||||
confirmPrepAddEmployees() {
|
||||
this.submitPrepAddEmployeesData.employeeIds = [];
|
||||
this.prepAddEmployees.forEach(e => {
|
||||
console.log(e);
|
||||
this.submitPrepAddEmployeesData.employeeIds.push(e.manageId);
|
||||
});
|
||||
console.log(this.prepAddEmployees);
|
||||
this.submitPrepAddEmployeesData.roleId = this.roleId;
|
||||
this.addEmployeeListRole(this.submitPrepAddEmployeesData);
|
||||
this.getListEmployee(this.employeeData); // 刷新表格
|
||||
},
|
||||
// 添加角色成员方法
|
||||
async addEmployeeListRole(param) {
|
||||
this.isShowTablesLoading = true;
|
||||
try {
|
||||
await roleApi.addEmployeeListRole(param);
|
||||
this.$Message.success('添加成功');
|
||||
this.employeeData.roleId = this.roleId;
|
||||
await this.getListEmployee(this.employeeData);
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
} finally {
|
||||
this.isShowTablesLoading = false;
|
||||
}
|
||||
},
|
||||
// 穿梭框穿梭方法
|
||||
addPrepEmployees() {
|
||||
let obj = this.$refs.departmentEmployeeTree.getSelect();
|
||||
let Obj = {};
|
||||
let notHave = true;
|
||||
Obj.manageName = obj.name;
|
||||
Obj.manageId = obj.id;
|
||||
for (let i = 0; i < this.prepAddEmployees.length; i++) {
|
||||
if (this.prepAddEmployees[i].manageId === Obj.manageId) {
|
||||
notHave = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (notHave === true) {
|
||||
notHave = false;
|
||||
this.submitPrepAddEmployeesData.employeeIds.push(Obj.manageId);
|
||||
this.prepAddEmployees.push(Obj);
|
||||
}
|
||||
},
|
||||
// 获取角色id对应的成员列表方法
|
||||
async getListEmployee(param) {
|
||||
this.isShowTablesLoading = true;
|
||||
try {
|
||||
let response = await roleApi.getListEmployee(param);
|
||||
this.roleList = response.data;
|
||||
this.total = response.data.total;
|
||||
this.pageSize = response.data.pageSize;
|
||||
this.tableData = this.roleList.list;
|
||||
await this.getListAllEmployee();
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
} finally {
|
||||
this.isShowTablesLoading = false;
|
||||
}
|
||||
},
|
||||
// 获取角色id对应的全部成员列表方法
|
||||
async getListAllEmployee() {
|
||||
this.$isShowTablesLoading = true;
|
||||
try {
|
||||
let response = await roleApi.getAllListEmployee(this.roleId);
|
||||
let list = response.data;
|
||||
this.prepAddEmployees = [];
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
let object = {};
|
||||
object.manageName = list[i].actualName;
|
||||
object.manageId = list[i].id;
|
||||
this.prepAddEmployees.push(object);
|
||||
}
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
} finally {
|
||||
this.isShowTablesLoading = false;
|
||||
}
|
||||
},
|
||||
// 添加成员方法,
|
||||
addEmployee() {
|
||||
this.isShowEmployeeModal = true;
|
||||
this.getListAllEmployee();
|
||||
this.submitPrepAddEmployeesData.employeeIds = [];
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped >
|
||||
.shuttle-box {
|
||||
position: relative;
|
||||
.box {
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 10px;
|
||||
height: 330px;
|
||||
}
|
||||
|
||||
.title {
|
||||
padding: 10px 0;
|
||||
background: #426783;
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,403 @@
|
||||
<template>
|
||||
<!--div 功能权限部分 start-->
|
||||
<div id="tree">
|
||||
<Row>
|
||||
<Col class="col-desc" span="16">设置角色对应的功能操作、后台管理权限</Col>
|
||||
<Col class="button-style" span="8">
|
||||
<Button
|
||||
@click.native="saveChange()"
|
||||
style="margin-right: 20px;"
|
||||
type="primary"
|
||||
v-privilege="'update-role-privilege'"
|
||||
>保存</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
<!--CheckboxGroup 功能权限勾选部分 start-->
|
||||
<CheckboxGroup v-model="checkedData">
|
||||
<div class="checked-box">
|
||||
<ul>
|
||||
<!--li 一级权限模块 start-->
|
||||
<li :key="module.key" v-for="(module, moduleIndex) in tree">
|
||||
<div class="level-one">
|
||||
<Checkbox
|
||||
:label="module.key"
|
||||
@click.prevent.native="selectCheckbox(tree, moduleIndex)"
|
||||
>{{module.name}}</Checkbox>
|
||||
</div>
|
||||
<!--div 二级权限模块 start-->
|
||||
<div
|
||||
:key="childrenModule.key"
|
||||
class="level-teo"
|
||||
v-for="(childrenModule, childrenModuleIndex) in module.children"
|
||||
>
|
||||
<Checkbox
|
||||
:label="childrenModule.key"
|
||||
@click.prevent.native="selectCheckbox(module.children,childrenModuleIndex,tree)"
|
||||
class="level-teo-label"
|
||||
>{{childrenModule.name}}</Checkbox>
|
||||
<!--div 三级权限模块 start-->
|
||||
<div class="level-three">
|
||||
<template v-for="(pages,pagesIndex) in childrenModule.children">
|
||||
<div
|
||||
:key="pages.key"
|
||||
class="isLevel-four"
|
||||
v-if="pages.children && pages.children.length > 0"
|
||||
>
|
||||
<Checkbox
|
||||
:key="pages.key"
|
||||
:label="pages.key"
|
||||
@click.prevent.native="selectCheckbox(childrenModule.children,pagesIndex,module.children)"
|
||||
class="level-three-label"
|
||||
>{{pages.name}}</Checkbox>
|
||||
<div :key="pagesIndex" class="Level-four" v-if="pages.children.length > 0">
|
||||
<template v-for="(page, pageIndex) in pages.children">
|
||||
<Checkbox
|
||||
:key="page.key"
|
||||
:label="page.key"
|
||||
@click.prevent.native="selectCheckbox(pages.children, pageIndex,childrenModule.children,module.children)"
|
||||
>{{page.name}}</Checkbox>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<Checkbox
|
||||
:key="pages.key"
|
||||
:label="pages.key"
|
||||
@click.prevent.native="selectCheckbox(childrenModule.children,pagesIndex,module.children)"
|
||||
v-else
|
||||
>{{pages.name}}</Checkbox>
|
||||
</template>
|
||||
</div>
|
||||
<!--div 三级权限模块 end-->
|
||||
</div>
|
||||
<!--div 二级权限模块 end-->
|
||||
</li>
|
||||
<!--li 一级权限模块 end-->
|
||||
</ul>
|
||||
</div>
|
||||
</CheckboxGroup>
|
||||
<!--CheckboxGroup 功能权限勾选部分 end-->
|
||||
</div>
|
||||
<!--div 功能权限部分 end-->
|
||||
</template>
|
||||
<script>
|
||||
import { roleApi } from '@/api/role';
|
||||
import { privilegeApi } from '@/api/privilege';
|
||||
|
||||
export default {
|
||||
name: 'RoleTree',
|
||||
props: {
|
||||
// 角色id
|
||||
roleId: {
|
||||
type: Number,
|
||||
required: true,
|
||||
validator: value => {
|
||||
return value >= 0;
|
||||
}
|
||||
}
|
||||
},
|
||||
components: {},
|
||||
// 父级组件数据传递
|
||||
data() {
|
||||
return {
|
||||
// 权限数据
|
||||
tree: [],
|
||||
loading: false,
|
||||
// 提交保存数据
|
||||
rolePower: {
|
||||
privilegeKeyList: [],
|
||||
roleId: ''
|
||||
},
|
||||
// 已选项
|
||||
checkedData: []
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {
|
||||
roleId(newVal) {
|
||||
if (newVal) {
|
||||
this.getListPrivilegeByRoleId(newVal);
|
||||
}
|
||||
}
|
||||
},
|
||||
filters: {},
|
||||
created() {},
|
||||
mounted() {
|
||||
this.getListPrivilegeByRoleId(this.roleId);
|
||||
},
|
||||
beforeCreate() {},
|
||||
beforeMount() {},
|
||||
beforeUpdate() {},
|
||||
updated() {},
|
||||
beforeDestroy() {},
|
||||
destroyed() {},
|
||||
activated() {},
|
||||
methods: {
|
||||
// 勾选权限
|
||||
selectCheckbox(
|
||||
currentModuleList,
|
||||
moduleIndex,
|
||||
upOneModuleList,
|
||||
upTwoModuleList
|
||||
) {
|
||||
let module = currentModuleList[moduleIndex];
|
||||
// 是否勾选
|
||||
let findIndex = this.checkedData.indexOf(module.key);
|
||||
if (findIndex !== -1) {
|
||||
this.spliceCheck(module);
|
||||
// 取消的上级ID
|
||||
// 判断同级是否全部已取消勾选
|
||||
let currentLevelAllUnchecked = this.isUnCheckedThisLevel(
|
||||
currentModuleList
|
||||
);
|
||||
if (currentLevelAllUnchecked && upOneModuleList) {
|
||||
// 判断上级是否全部已取消勾选
|
||||
let upOneLevelAllUnchecked = this.isUnCheckedThisLevel(
|
||||
upOneModuleList
|
||||
);
|
||||
if (upOneLevelAllUnchecked && upTwoModuleList) {
|
||||
// 判断上上级是否全部已取消勾选
|
||||
this.isUnCheckedThisLevel(upTwoModuleList);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 选中子级所有checkBox
|
||||
this.addCheck(module);
|
||||
// 选中上级组件
|
||||
if (module.parentKey) {
|
||||
if (
|
||||
this.checkedData.findIndex(val => val === module.parentKey) === -1
|
||||
) {
|
||||
this.checkedData.push(module.parentKey);
|
||||
}
|
||||
}
|
||||
// 选中上上级组件
|
||||
if (upOneModuleList) {
|
||||
let upOneFindIndex = upOneModuleList.findIndex(
|
||||
e => e.key === module.parentKey
|
||||
);
|
||||
let upOneFind =
|
||||
upOneFindIndex === -1 ? null : upOneModuleList[upOneFindIndex];
|
||||
if (
|
||||
upOneFind &&
|
||||
upOneFind.parentKey &&
|
||||
this.checkedData.findIndex(val => val === upOneFind.parentKey) ===
|
||||
-1
|
||||
) {
|
||||
this.checkedData.push(upOneFind.parentKey);
|
||||
}
|
||||
// 选中上上上级组件
|
||||
if (upTwoModuleList) {
|
||||
console.log(1111, upTwoModuleList, upOneFind);
|
||||
let upTwoFindIndex = upTwoModuleList.findIndex(
|
||||
e => e.key === upOneFind.parentKey
|
||||
);
|
||||
let upTwoFind =
|
||||
upTwoFindIndex === -1 ? null : upTwoModuleList[upTwoFindIndex];
|
||||
if (
|
||||
upTwoFind &&
|
||||
upTwoFind.parentKey &&
|
||||
this.checkedData.findIndex(val => val === upTwoFind.parentKey) ===
|
||||
-1
|
||||
) {
|
||||
this.checkedData.push(upTwoFind.parentKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// 判断同级是否全部已取消勾选
|
||||
isUnCheckedThisLevel(moduleList) {
|
||||
let thisLevelAllUnchecked = true;
|
||||
moduleList.forEach(e => {
|
||||
let brotherIndex = this.checkedData.findIndex(val => val == e.key);
|
||||
if (brotherIndex != -1) {
|
||||
thisLevelAllUnchecked = false;
|
||||
}
|
||||
});
|
||||
if (thisLevelAllUnchecked) {
|
||||
let number = this.checkedData.findIndex(
|
||||
e => e == moduleList[0].parentKey
|
||||
);
|
||||
if (number != -1) {
|
||||
this.checkedData.splice(number, 1);
|
||||
}
|
||||
}
|
||||
return thisLevelAllUnchecked;
|
||||
},
|
||||
// 选中子级所有checkBox
|
||||
addCheck(module) {
|
||||
let findIndex = this.checkedData.findIndex(val => val == module.key);
|
||||
if (findIndex == -1) {
|
||||
this.checkedData.push(module.key);
|
||||
}
|
||||
if (module.children) {
|
||||
module.children.forEach(item => {
|
||||
this.addCheck(item);
|
||||
});
|
||||
}
|
||||
},
|
||||
// 取消自己和下级勾选
|
||||
spliceCheck(module) {
|
||||
let findIndex = this.checkedData.findIndex(val => val == module.key);
|
||||
if (findIndex != -1) {
|
||||
this.checkedData.splice(findIndex, 1);
|
||||
}
|
||||
if (module.children) {
|
||||
module.children.forEach(item => {
|
||||
this.spliceCheck(item);
|
||||
});
|
||||
}
|
||||
},
|
||||
// 保存改变权限
|
||||
saveChange() {
|
||||
if (this.checkedData.length == 0) {
|
||||
this.$Message.error('还未选择任何权限');
|
||||
return;
|
||||
}
|
||||
this.rolePower.roleId = this.roleId;
|
||||
this.rolePower.privilegeKeyList = this.checkedData.concat();
|
||||
this.getRolePower(this.rolePower);
|
||||
},
|
||||
// 更新角色功能权限方法
|
||||
async getRolePower(data) {
|
||||
this.$Spin.show();
|
||||
try {
|
||||
await privilegeApi.getRolePower(data);
|
||||
this.$Message.info('保存成功');
|
||||
this.rolePower.privilegeKeyList = [];
|
||||
await this.getListPrivilegeByRoleId(this.roleId);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
this.$Spin.hide();
|
||||
}
|
||||
},
|
||||
// 获取角色可选的功能权限
|
||||
async getListPrivilegeByRoleId(id) {
|
||||
try {
|
||||
let response = await privilegeApi.getListPrivilegeByRoleId(id);
|
||||
let datas = response.data;
|
||||
this.tree = datas.privilege;
|
||||
console.log('tree', this.tree);
|
||||
this.checkedData = datas.selectedKey || [];
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
#tree {
|
||||
border: 1px solid #dcdee2;
|
||||
border-top: none;
|
||||
}
|
||||
.col-desc {
|
||||
margin: 20px 0;
|
||||
font-size: 15px;
|
||||
color: #95a5a6;
|
||||
padding: 0 20px;
|
||||
}
|
||||
.button-style {
|
||||
margin: 20px 0 20px 0;
|
||||
padding-left: 20px;
|
||||
text-align: right;
|
||||
}
|
||||
.check-right {
|
||||
margin-right: 20px;
|
||||
}
|
||||
.row-border {
|
||||
border: 1px solid #f0f0f0;
|
||||
}
|
||||
.col-border {
|
||||
line-height: 50px;
|
||||
padding-left: 20px;
|
||||
border-right: 1px solid #f0f0f0;
|
||||
}
|
||||
.col-left {
|
||||
line-height: 50px;
|
||||
padding-left: 40px;
|
||||
border-right: 1px solid #f0f0f0;
|
||||
}
|
||||
.col-right {
|
||||
padding-left: 20px;
|
||||
border-right: 1px solid #f0f0f0;
|
||||
}
|
||||
.ivu-tree ul li {
|
||||
white-space: normal;
|
||||
}
|
||||
.ivu-tree {
|
||||
> ul {
|
||||
> li {
|
||||
> ul {
|
||||
> li {
|
||||
.ivu-tree-title {
|
||||
vertical-align: middle;
|
||||
font-weight: bold;
|
||||
}
|
||||
> ul {
|
||||
display: inline-block;
|
||||
.ivu-tree-title {
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.checked-box {
|
||||
padding: 0 15px;
|
||||
ul {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
li {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
.level-one {
|
||||
border-bottom: 1px solid rgb(240, 240, 240);
|
||||
padding: 10px 0;
|
||||
}
|
||||
.level-teo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 4%;
|
||||
position: relative;
|
||||
border-bottom: 1px solid rgb(240, 240, 240);
|
||||
line-height: 40px;
|
||||
.level-teo-label {
|
||||
width: 12%;
|
||||
min-width: 120px;
|
||||
}
|
||||
// &:before{ content: ''; position: absolute; height: 100%; width: 1px; background: rgb(240, 240, 240); left: 12%; top: 0; }
|
||||
.level-three {
|
||||
padding-left: 4%;
|
||||
display: block;
|
||||
flex: 1;
|
||||
min-height: 40px;
|
||||
border-left: 1px rgb(240, 240, 240) solid;
|
||||
.isLevel-four {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.level-three-label {
|
||||
width: 12%;
|
||||
min-width: 120px;
|
||||
}
|
||||
.Level-four {
|
||||
padding-left: 4%;
|
||||
flex: 1;
|
||||
min-height: 40px;
|
||||
border-left: 1px rgb(240, 240, 240) solid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.ivu-checkbox-wrapper {
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
339
smart-admin-web/src/views/employee/role/role-manage.vue
Normal file
339
smart-admin-web/src/views/employee/role/role-manage.vue
Normal file
@@ -0,0 +1,339 @@
|
||||
<template>
|
||||
<!-- Row 角色管理 start -->
|
||||
<Row :gutter="10">
|
||||
<!-- Col 左侧角色列表模块 start -->
|
||||
<Col :lg="5" :md="8">
|
||||
<Card class="warp-card" dis-hover style=" position: relative;">
|
||||
<p slot="title">角色列表</p>
|
||||
<div slot="extra">
|
||||
<Button
|
||||
@click="showAddRoleModal()"
|
||||
size="small"
|
||||
type="primary"
|
||||
v-privilege="'add-role'"
|
||||
>添加</Button>
|
||||
</div>
|
||||
<!-- Menu 角色列表 start -->
|
||||
<Menu
|
||||
:active-name="0"
|
||||
class="left role-list no-scrollbar"
|
||||
ref="sideMenu"
|
||||
style="height: 666px;overflow-y: scroll;width:100%;"
|
||||
>
|
||||
<!-- MenuItem 角色列表项 start -->
|
||||
<MenuItem
|
||||
:key="item.id"
|
||||
:name="index"
|
||||
@click.native="selectRole(item,index)"
|
||||
v-for="(item,index) in roleList"
|
||||
>
|
||||
<Row>
|
||||
<Col span="24">
|
||||
<span class="role-name">
|
||||
<Tooltip placement="right">
|
||||
<span>{{item.roleName}}</span>
|
||||
<div class="suspension-box" slot="content">
|
||||
<p>
|
||||
<span @click="deleteSingleRole(item)" v-privilege="'delete-role'">删除</span>
|
||||
</p>
|
||||
<p>
|
||||
<span @click="showUpdateRoleModal(item)" v-privilege="'update-role'">编辑</span>
|
||||
</p>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</span>
|
||||
</Col>
|
||||
</Row>
|
||||
</MenuItem>
|
||||
<!-- MenuItem 角色列表项 end -->
|
||||
</Menu>
|
||||
<!-- Menu 角色列表 end -->
|
||||
<!--Modal 添加角色 start-->
|
||||
<Modal title="添加角色" v-model="isShowAddRoleModal">
|
||||
<Form :label-width="100" :model="ruleDetail" label-position="left">
|
||||
<FormItem label="角色名称" required>
|
||||
<Input
|
||||
@on-keydown="ruleDetail.name=ruleDetail.name.replace(/^ +| +$/g,'')"
|
||||
@on-keyup="ruleDetail.name=ruleDetail.name.replace(/^ +| +$/g,'')"
|
||||
placeholder="请输入角色名称..."
|
||||
v-model="ruleDetail.name"
|
||||
></Input>
|
||||
</FormItem>
|
||||
<FormItem label="备注">
|
||||
<Input placeholder="请输入备注" type="textarea" v-model="ruleDetail.detail"></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer">
|
||||
<Button @click="submitRole" type="primary">确认</Button>
|
||||
<Button @click="hideAddRoleModal()">返回</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
<!--Modal 添加角色 end-->
|
||||
<!--Modal 修改角色 start-->
|
||||
<Modal title="修改角色" v-model="isShowUpdateRoleModal">
|
||||
<Form :label-width="100" :model="ruleDetail" label-position="left">
|
||||
<FormItem label="角色名称" required>
|
||||
<Input
|
||||
@on-keydown="ruleDetail.name=ruleDetail.name.replace(/^ +| +$/g,'')"
|
||||
@on-keyup="ruleDetail.name=ruleDetail.name.replace(/^ +| +$/g,'')"
|
||||
placeholder="请输入角色名称..."
|
||||
v-model="ruleDetail.name"
|
||||
></Input>
|
||||
</FormItem>
|
||||
<FormItem label="备注">
|
||||
<Input placeholder="请输入备注" type="textarea" v-model="ruleDetail.detail"></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer">
|
||||
<Button @click="updateRole" type="primary">确认</Button>
|
||||
<Button @click="hideUpdateRoleModal()">返回</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
<!--Modal 修改角色 end-->
|
||||
<!--Modal 删除角色 start-->
|
||||
<Modal
|
||||
@on-cancel="cancelDeleteRole()"
|
||||
@on-ok="confirmDeleteRole()"
|
||||
title="删除角色"
|
||||
v-model="isShowRemoveRoleModal"
|
||||
>确定删除"{{ruleDetail.name}}"这个角色吗?</Modal>
|
||||
<!--Modal 删除角色 end-->
|
||||
</Card>
|
||||
</Col>
|
||||
<!-- Col 左侧角色列表模块 end -->
|
||||
<!-- Col 功能列表 start -->
|
||||
<Col :lg="19" :md="16">
|
||||
<Card class="warp-card" dis-hover>
|
||||
<div class="card-title" slot="title">功能列表</div>
|
||||
<!-- Menu 切换功能 start -->
|
||||
<Menu :active-name="displayTab" @on-select="selectTab" mode="horizontal" style="z-index: 1">
|
||||
<MenuItem :name="1">
|
||||
<Icon type="ios-hammer" />功能权限
|
||||
</MenuItem>
|
||||
<MenuItem :name="2">
|
||||
<Icon type="ios-paper" />数据范围
|
||||
</MenuItem>
|
||||
<MenuItem :name="3">
|
||||
<Icon type="ios-people" />成员管理
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
<!-- Menu 切换功能 end -->
|
||||
<!--功能权限-->
|
||||
<RoleTree :roleId="roleId" v-if="displayTab==1"></RoleTree>
|
||||
<!--数据范围-->
|
||||
<RoleDataScope :roleId="roleId" v-if="displayTab==2"></RoleDataScope>
|
||||
<!--成员管理-->
|
||||
<RoleList :roleId="roleId" v-if="displayTab==3"></RoleList>
|
||||
</Card>
|
||||
</Col>
|
||||
<!-- Col 功能列表 end -->
|
||||
</Row>
|
||||
<!-- Row 角色管理 end -->
|
||||
</template>
|
||||
<script>
|
||||
import RoleTree from './components/role-tree/role-tree';
|
||||
import RoleList from './components/role-list/role-list';
|
||||
import RoleDataScope from './components/role-data-scope/role-data-scope';
|
||||
import { roleApi } from '@/api/role';
|
||||
|
||||
export default {
|
||||
name: 'RoleManage',
|
||||
components: {
|
||||
RoleTree,
|
||||
RoleList,
|
||||
RoleDataScope
|
||||
},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
roleList: {},
|
||||
roleId: 0,
|
||||
// 删除角色对话框隐藏
|
||||
isShowRemoveRoleModal: false,
|
||||
// 修改角色对话框隐藏
|
||||
isShowUpdateRoleModal: false,
|
||||
// 增加角色对话框隐藏
|
||||
isShowAddRoleModal: false,
|
||||
// 增加角色信息
|
||||
ruleDetail: {
|
||||
name: '',
|
||||
id: '',
|
||||
detail: ''
|
||||
},
|
||||
// 默认选中Menu标签为功能权限
|
||||
displayTab: 1,
|
||||
// 是否第一次请求数据
|
||||
isFirst: true
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
filters: {},
|
||||
created() {},
|
||||
mounted() {
|
||||
// 初始化加载数据
|
||||
this.getAllRole();
|
||||
},
|
||||
beforeCreate() {},
|
||||
beforeMount() {},
|
||||
beforeUpdate() {},
|
||||
updated() {},
|
||||
beforeDestroy() {},
|
||||
destroyed() {},
|
||||
activated() {},
|
||||
methods: {
|
||||
// 初始化加载数据方法
|
||||
async getAllRole() {
|
||||
try {
|
||||
let response = await roleApi.getAllRole();
|
||||
this.roleList = response.data;
|
||||
if (this.roleList && this.roleList.length > 0) {
|
||||
this.roleId = this.roleList[0].id;
|
||||
if (this.isFirst) {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.sideMenu.updateOpened();
|
||||
this.$refs.sideMenu.updateActiveName();
|
||||
});
|
||||
this.isFirst = false;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
}
|
||||
},
|
||||
// 增加角色方法
|
||||
async addRole(roleDesc, roleName) {
|
||||
this.$Spin.show();
|
||||
try {
|
||||
await roleApi.addRole(roleDesc, roleName);
|
||||
this.hideAddRoleModal();
|
||||
await this.getAllRole(); // 刷新
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
} finally {
|
||||
this.$Spin.hide();
|
||||
}
|
||||
},
|
||||
// 提交添加角色
|
||||
submitRole() {
|
||||
// 添加
|
||||
if (this.ruleDetail.name !== '' && this.ruleDetail.name.length <= 20) {
|
||||
this.addRole(this.ruleDetail.detail, this.ruleDetail.name);
|
||||
} else {
|
||||
this.$Message.warning('请先完善角色信息');
|
||||
}
|
||||
},
|
||||
// 编辑角色方法
|
||||
async updateRole() {
|
||||
this.$Spin.show();
|
||||
try {
|
||||
let response = await roleApi.updateRole(
|
||||
this.ruleDetail.id,
|
||||
this.ruleDetail.detail,
|
||||
this.ruleDetail.name
|
||||
);
|
||||
this.roleList = response.data;
|
||||
this.hideUpdateRoleModal();
|
||||
await this.getAllRole(); // 刷新
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
} finally {
|
||||
this.$Spin.hide();
|
||||
}
|
||||
},
|
||||
// 删除角色方法
|
||||
async deleteRole(id) {
|
||||
this.$Spin.show();
|
||||
try {
|
||||
await roleApi.deleteRole(id);
|
||||
this.$Message.success('删除成功');
|
||||
await this.getAllRole(); // 刷新
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
} finally {
|
||||
this.$Spin.hide();
|
||||
}
|
||||
},
|
||||
// 删除单个角色
|
||||
deleteSingleRole(item) {
|
||||
this.isShowRemoveRoleModal = true;
|
||||
this.ruleDetail.id = item.id;
|
||||
this.ruleDetail.name = item.roleName;
|
||||
},
|
||||
// 编辑角色页面
|
||||
showUpdateRoleModal(item) {
|
||||
console.log(item);
|
||||
this.isShowUpdateRoleModal = true;
|
||||
this.ruleDetail.id = item.id;
|
||||
this.ruleDetail.name = item.roleName;
|
||||
this.ruleDetail.detail = item.remark;
|
||||
},
|
||||
// 添加角色页面
|
||||
showAddRoleModal() {
|
||||
this.isShowAddRoleModal = true;
|
||||
this.ruleDetail.name = '';
|
||||
this.ruleDetail.detail = '';
|
||||
},
|
||||
// 关闭更新弹窗
|
||||
hideUpdateRoleModal() {
|
||||
this.isShowUpdateRoleModal = false;
|
||||
},
|
||||
// 关闭添加弹窗
|
||||
hideAddRoleModal() {
|
||||
this.isShowAddRoleModal = false;
|
||||
},
|
||||
// 功能选择
|
||||
selectTab(position) {
|
||||
this.displayTab = position;
|
||||
},
|
||||
// 角色选择
|
||||
selectRole(item, index) {
|
||||
this.roleId = item.id;
|
||||
},
|
||||
// 确定删除
|
||||
confirmDeleteRole() {
|
||||
this.deleteRole(this.ruleDetail.id);
|
||||
this.isShowRemoveRoleModal = false;
|
||||
},
|
||||
// 取消删除
|
||||
cancelDeleteRole() {
|
||||
this.isShowRemoveRoleModal = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.role-list {
|
||||
line-height: 30px;
|
||||
padding: 10px 0;
|
||||
|
||||
.role-name {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-left: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.ivu-menu-item-active:not(.ivu-menu-submenu) {
|
||||
z-index: 0 !important;
|
||||
}
|
||||
|
||||
.suspension-box {
|
||||
z-index: 999;
|
||||
padding: 0 8px;
|
||||
|
||||
p {
|
||||
padding: 3px 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
19
smart-admin-web/src/views/error-page/401.vue
Normal file
19
smart-admin-web/src/views/error-page/401.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<error-content code="401" desc="Oh~~您没有浏览这个页面的权限~" :src="src" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import error401 from '@/assets/images/error-page/error-401.svg';
|
||||
import ErrorContent from './error-content.vue';
|
||||
export default {
|
||||
name: 'error401',
|
||||
components: {
|
||||
ErrorContent
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
src: error401
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
19
smart-admin-web/src/views/error-page/404.vue
Normal file
19
smart-admin-web/src/views/error-page/404.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<error-content code="404" desc="Oh~~您的页面好像飞走了~" :src="src" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import error404 from '@/assets/images/error-page/error-404.svg';
|
||||
import ErrorContent from './error-content.vue';
|
||||
export default {
|
||||
name: 'error404',
|
||||
components: {
|
||||
ErrorContent
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
src: error404
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
19
smart-admin-web/src/views/error-page/500.vue
Normal file
19
smart-admin-web/src/views/error-page/500.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<error-content code="500" desc="Oh~~鬼知道服务器经历了什么~" :src="src"/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import error404 from '@/assets/images/error-page/error-500.svg';
|
||||
import ErrorContent from './error-content.vue';
|
||||
export default {
|
||||
name: 'error500',
|
||||
components: {
|
||||
ErrorContent
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
src: error404
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
40
smart-admin-web/src/views/error-page/back-btn-group.vue
Normal file
40
smart-admin-web/src/views/error-page/back-btn-group.vue
Normal file
@@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<div>
|
||||
<Button size="large" type="text" @click="backHome">返回首页</Button>
|
||||
<Button size="large" type="text" @click="backPrev">返回上一页({{ second }}s)</Button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import './error.less';
|
||||
export default {
|
||||
name: 'backBtnGroup',
|
||||
data () {
|
||||
return {
|
||||
second: 5,
|
||||
timer: null
|
||||
};
|
||||
},
|
||||
mounted () {
|
||||
this.timer = setInterval(() => {
|
||||
if (this.second === 0) this.backPrev();
|
||||
else this.second--;
|
||||
}, 1000);
|
||||
},
|
||||
beforeDestroy () {
|
||||
clearInterval(this.timer);
|
||||
},
|
||||
methods: {
|
||||
// 回到首页
|
||||
backHome () {
|
||||
this.$router.replace({
|
||||
name: this.$config.homeName
|
||||
});
|
||||
},
|
||||
// 返回上一页
|
||||
backPrev () {
|
||||
this.$router.go(-1);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
28
smart-admin-web/src/views/error-page/error-content.vue
Normal file
28
smart-admin-web/src/views/error-page/error-content.vue
Normal file
@@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<div class="error-page">
|
||||
<div class="content-con">
|
||||
<img :src="src" :alt="code">
|
||||
<div class="text-con">
|
||||
<h4>{{ code }}</h4>
|
||||
<h5>{{ desc }}</h5>
|
||||
</div>
|
||||
<back-btn-group class="back-btn-group"></back-btn-group>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import './error.less';
|
||||
import BackBtnGroup from './back-btn-group.vue';
|
||||
export default {
|
||||
name: 'errorContent',
|
||||
components: {
|
||||
BackBtnGroup
|
||||
},
|
||||
props: {
|
||||
code: String,
|
||||
desc: String,
|
||||
src: String
|
||||
}
|
||||
};
|
||||
</script>
|
||||
46
smart-admin-web/src/views/error-page/error.less
Normal file
46
smart-admin-web/src/views/error-page/error.less
Normal file
@@ -0,0 +1,46 @@
|
||||
.error-page{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
background: #f8f8f9;
|
||||
.content-con{
|
||||
width: 700px;
|
||||
height: 600px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -60%);
|
||||
img{
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.text-con{
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
h4{
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
font-size: 80px;
|
||||
font-weight: 700;
|
||||
color: #348EED;
|
||||
}
|
||||
h5{
|
||||
position: absolute;
|
||||
width: 700px;
|
||||
left: 0px;
|
||||
top: 100px;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: #67647D;
|
||||
}
|
||||
}
|
||||
.back-btn-group{
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
bottom: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
279
smart-admin-web/src/views/file/file-list.vue
Normal file
279
smart-admin-web/src/views/file/file-list.vue
Normal file
@@ -0,0 +1,279 @@
|
||||
<template>
|
||||
<div>
|
||||
<Card class="warp-card" dis-hover>
|
||||
<Form :model="searchForm" class="tools" inline ref="searchForm">
|
||||
<FormItem prop="fileName">
|
||||
<Input placeholder="请输入文件名" type="text" v-model="searchForm.fileName" />
|
||||
</FormItem>
|
||||
<FormItem prop="sendStatus">
|
||||
<Select placeholder="请选择业务类型" style="width:200px" v-model="searchForm.moduleType">
|
||||
<Option value>全部</Option>
|
||||
<Option :key="item.value" :value="item.value" v-for="item in moduleTypes">{{item.desc}}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem prop="sendStatus">
|
||||
<Select placeholder="请选择文件上传位置" style="width:200px" v-model="searchForm.fileLocationType">
|
||||
<Option value>全部</Option>
|
||||
<Option
|
||||
:key="item.value"
|
||||
:value="item.value"
|
||||
v-for="item in fileLocationTypes"
|
||||
>{{item.desc}}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<ButtonGroup>
|
||||
<Button
|
||||
@click="find"
|
||||
icon="ios-search"
|
||||
type="primary"
|
||||
v-privilege="'file-filePage-query'"
|
||||
>查询</Button>
|
||||
<Button
|
||||
@click="reset"
|
||||
icon="md-refresh"
|
||||
type="default"
|
||||
v-privilege="'file-filePage-query'"
|
||||
>重置</Button>
|
||||
</ButtonGroup>
|
||||
</FormItem>
|
||||
<FormItem v-privilege="'file-filePage-upload'">
|
||||
<Upload
|
||||
:action="uploadUrl"
|
||||
:headers="uploadHeader"
|
||||
:onError="uploadError"
|
||||
:onSuccess="uploadSuccess"
|
||||
:showUploadList="false"
|
||||
>
|
||||
<Button icon="ios-cloud-upload-outline" type="primary">上传新文件</Button>
|
||||
</Upload>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<Table :columns="columns" :data="tableData" :loading="tableLoading"></Table>
|
||||
<Page
|
||||
:current="searchForm.pageNum"
|
||||
:page-size="searchForm.pageSize"
|
||||
:page-size-opts="[10, 20, 30, 50, 100]"
|
||||
:total="total"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
show-elevator
|
||||
show-sizer
|
||||
show-total
|
||||
style="margin:24px 0;text-align:right;"
|
||||
></Page>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fileApi } from '@/api/file.js';
|
||||
import { FILE_TYPE, SERVICE_TYPE } from '@/constants/file';
|
||||
import Cookies from 'js-cookie';
|
||||
import { TOKEN_KEY } from '@/lib/cookie';
|
||||
export default {
|
||||
name: 'FileList',
|
||||
data() {
|
||||
let that = this;
|
||||
return {
|
||||
// 数据量
|
||||
total: null,
|
||||
// 文件表格加载
|
||||
tableLoading: false,
|
||||
// 查询参数
|
||||
searchForm: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
// 是否查询总条数
|
||||
searchCount: true,
|
||||
fileName: null,
|
||||
// 业务类型 BACK_USER:1 backUser/config
|
||||
moduleType: 1,
|
||||
// 文件位置 LOCAL:1 本地文件服务 ALI_OSS:2 阿里OSS文件服务 QI_NIU_OSS:3七牛文件服务
|
||||
fileLocationType: null
|
||||
},
|
||||
// 表头
|
||||
columns: [
|
||||
{
|
||||
title: '业务类型',
|
||||
key: 'moduleType',
|
||||
render(h, params) {
|
||||
return h('span', {}, that.getModuleTypeDesc(params.row.moduleType));
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '文件位置',
|
||||
key: 'fileLocationType',
|
||||
render(h, params) {
|
||||
return h(
|
||||
'span',
|
||||
{},
|
||||
that.getFileLocationTypeDesc(params.row.fileLocationType)
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '文件名称',
|
||||
key: 'fileName'
|
||||
},
|
||||
{
|
||||
title: '上传时间',
|
||||
key: 'createTime'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 160,
|
||||
align: 'center',
|
||||
className: 'action-hide',
|
||||
render: (h, params) => {
|
||||
return this.$tableAction(h, [
|
||||
{
|
||||
title: '下载',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'file-filePage-download'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.downloadFile(params.row.id);
|
||||
}
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
],
|
||||
// table数据
|
||||
tableData: []
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
uploadHeader: function() {
|
||||
let header = {
|
||||
'x-access-token': Cookies.get(TOKEN_KEY)
|
||||
};
|
||||
return header;
|
||||
},
|
||||
uploadUrl: function() {
|
||||
let baseUrl = fileApi.fileUploadLocalUrl;
|
||||
switch (this.searchForm.fileLocationType) {
|
||||
case 2:
|
||||
baseUrl = fileApi.fileUploadAliUrl;
|
||||
break;
|
||||
case 3:
|
||||
baseUrl = fileApi.fileUploadQiNiuUrl;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
let url = baseUrl + this.searchForm.moduleType;
|
||||
return url;
|
||||
},
|
||||
// 文件业务类型
|
||||
moduleTypes: function() {
|
||||
let array = [];
|
||||
for (let item in SERVICE_TYPE) {
|
||||
let obj = {};
|
||||
obj.desc = SERVICE_TYPE[item].desc;
|
||||
obj.value = SERVICE_TYPE[item].value;
|
||||
array.push(obj);
|
||||
}
|
||||
return array;
|
||||
},
|
||||
fileLocationTypes: function() {
|
||||
let array = [];
|
||||
for (const item in FILE_TYPE) {
|
||||
let obj = {};
|
||||
obj.desc = FILE_TYPE[item].desc;
|
||||
obj.value = FILE_TYPE[item].value;
|
||||
array.push(obj);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getFileList();
|
||||
},
|
||||
methods: {
|
||||
// 上传成功钩子
|
||||
async uploadSuccess(e) {
|
||||
if (!e.success) {
|
||||
console.error(e);
|
||||
return this.uploadError();
|
||||
}
|
||||
this.$Spin.show();
|
||||
let reqBody = {
|
||||
moduleId: 1,
|
||||
moduleType: this.searchForm.moduleType ? this.searchForm.moduleType : 1,
|
||||
fileLocationType: this.searchForm.fileLocationType
|
||||
? this.searchForm.fileLocationType
|
||||
: 1,
|
||||
fileName: e.data.fileName,
|
||||
filePath: e.data.filePath
|
||||
};
|
||||
let rep = await fileApi.addFile(reqBody);
|
||||
this.$Spin.hide();
|
||||
this.$Message.success('上传成功');
|
||||
this.find();
|
||||
},
|
||||
// 上传失败钩子
|
||||
uploadError(e) {
|
||||
this.$Message.error('上传出错,请重试!');
|
||||
console.error(e);
|
||||
this.find();
|
||||
},
|
||||
// 下载文件
|
||||
downloadFile(id) {
|
||||
fileApi.downLoadFile(id);
|
||||
},
|
||||
// 根据数字获取业务类型描述
|
||||
getModuleTypeDesc(value) {
|
||||
return this.$enum.getDescByValue('SERVICE_TYPE', value);
|
||||
},
|
||||
// 根据数字获取文件位置描述
|
||||
getFileLocationTypeDesc(value) {
|
||||
return this.$enum.getDescByValue('FILE_TYPE', value);
|
||||
},
|
||||
// 重置
|
||||
reset() {
|
||||
this.searchForm.fileName = null;
|
||||
this.searchForm.moduleType = 1;
|
||||
this.searchForm.fileLocationType = null;
|
||||
this.$refs.searchForm.resetFields();
|
||||
this.find();
|
||||
},
|
||||
// 查询
|
||||
find() {
|
||||
this.searchForm.pageNum = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.getFileList();
|
||||
},
|
||||
// 更改分页查询条数
|
||||
changePageSize(pageSize) {
|
||||
this.searchForm.pageNum = 1;
|
||||
this.searchForm.pageSize = pageSize;
|
||||
this.getFileList();
|
||||
},
|
||||
// 获取文件数据
|
||||
async getFileList() {
|
||||
try {
|
||||
this.tableLoading = true;
|
||||
let res = await fileApi.queryFileList(this.searchForm);
|
||||
this.tableData = res.data.list;
|
||||
this.total = res.data.total;
|
||||
this.tableLoading = false;
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
this.tableLoading = false;
|
||||
}
|
||||
},
|
||||
// 页码改变
|
||||
changePage(pageNum) {
|
||||
this.searchForm.pageNum = pageNum;
|
||||
this.getFileList();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
115
smart-admin-web/src/views/heart-beat/heart-beat-list.vue
Normal file
115
smart-admin-web/src/views/heart-beat/heart-beat-list.vue
Normal file
@@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<Card class="warp-card" dis-hover>
|
||||
<Form class="tools" inline>
|
||||
<FormItem>
|
||||
<Button
|
||||
@click="queryHeartBeatRecord"
|
||||
icon="md-refresh"
|
||||
type="primary"
|
||||
v-privilege="'heart-beat-query'"
|
||||
>刷新</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<Alert>
|
||||
<h3>Smart-Heart-Beat 心跳服务介绍:</h3>
|
||||
<pre>
|
||||
简介:Smart-Heart-Beat 是心跳服务,用于监测Java应用的状态等其他信息。
|
||||
|
||||
原理:
|
||||
- Java后端会在项目启动的时候开启一个线程,每隔一段时间将该应用的IP、进程号更新到数据库t_heart_beat_record表中。
|
||||
用途:
|
||||
· 在各个环境(无论开发、测试、生产)能统一看到所有启动的服务列表。
|
||||
· 检测Java应用是否存活。
|
||||
· ※强烈推荐※ 当某些业务只允许有一个服务启动的时候,用于排查是否别人也启动的服务!!
|
||||
</pre>
|
||||
</Alert>
|
||||
<Table :columns="columns" :data="tableData" :loading="tableLoading" border></Table>
|
||||
<Page
|
||||
:current="searchFrom.pageNum"
|
||||
:page-size="searchFrom.pageSize"
|
||||
:show-sizer="true"
|
||||
:show-total="true"
|
||||
:total="pageTotal"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
style="margin:24px 0;text-align:right;"
|
||||
></Page>
|
||||
</Card>
|
||||
</template>
|
||||
<script>
|
||||
import { heartBeatApi } from '@/api/heart-beat';
|
||||
|
||||
export default {
|
||||
name: 'HeartBeatList',
|
||||
components: {},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
searchFrom: {
|
||||
pageSize: 10,
|
||||
pageNum: 1
|
||||
},
|
||||
tableLoading: false,
|
||||
pageTotal: 1,
|
||||
tableData: [],
|
||||
columns: [
|
||||
{
|
||||
title: 'Id',
|
||||
key: 'id',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '路径',
|
||||
key: 'projectPath'
|
||||
},
|
||||
{
|
||||
title: '进程号',
|
||||
key: 'processNo'
|
||||
},
|
||||
{
|
||||
title: '服务器ip',
|
||||
key: 'serverIp'
|
||||
},
|
||||
{
|
||||
title: '进程启动时间',
|
||||
key: 'processStartTime'
|
||||
},
|
||||
{
|
||||
title: '心跳时间 ',
|
||||
key: 'heartBeatTime'
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.queryHeartBeatRecord();
|
||||
},
|
||||
methods: {
|
||||
// 查询心跳记录
|
||||
async queryHeartBeatRecord() {
|
||||
try {
|
||||
this.tableLoading = true;
|
||||
let result = await heartBeatApi.queryHeartBeatRecord(this.searchFrom);
|
||||
this.tableData = result.data.list;
|
||||
this.pageTotal = result.data.total;
|
||||
this.tableLoading = false;
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
this.tableLoading = false;
|
||||
}
|
||||
},
|
||||
// 页码改变
|
||||
changePage(pageNum) {
|
||||
this.searchFrom.pageNum = pageNum;
|
||||
this.queryHeartBeatRecord();
|
||||
},
|
||||
// 改变每页显示数据条数
|
||||
changePageSize(pageSize) {
|
||||
this.searchFrom.pageNum = 1;
|
||||
this.searchFrom.pageSize = pageSize;
|
||||
this.queryHeartBeatRecord();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
43
smart-admin-web/src/views/home/components/card.vue
Normal file
43
smart-admin-web/src/views/home/components/card.vue
Normal file
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<div class="card-main">
|
||||
<div class="title">
|
||||
{{title}}
|
||||
<span>{{desc}}</span>
|
||||
</div>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: '标题'
|
||||
},
|
||||
desc: {
|
||||
type: String,
|
||||
default: '描述'
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang='less'>
|
||||
.card-main {
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.title {
|
||||
color: #060606;
|
||||
font-size: 16px;
|
||||
padding: 20px 32px;
|
||||
span {
|
||||
padding-left: 17px;
|
||||
font-size: 12px;
|
||||
color: #dededf;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
140
smart-admin-web/src/views/home/components/chart-bar.vue
Normal file
140
smart-admin-web/src/views/home/components/chart-bar.vue
Normal file
@@ -0,0 +1,140 @@
|
||||
<template>
|
||||
<div class="bar-main"
|
||||
id="box"
|
||||
ref="dom"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import echarts from 'echarts';
|
||||
import tdTheme from './theme.json';
|
||||
import { on, off } from '@/lib/util';
|
||||
echarts.registerTheme('tdTheme', tdTheme);
|
||||
export default {
|
||||
props: {
|
||||
value: Object,
|
||||
text: String,
|
||||
subtext: String
|
||||
},
|
||||
mounted() {
|
||||
this.initChart();
|
||||
},
|
||||
methods: {
|
||||
resize() {
|
||||
this.dom.resize();
|
||||
},
|
||||
initChart() {
|
||||
this.$nextTick(() => {
|
||||
let xAxisData = Object.keys(this.value);
|
||||
let seriesData = Object.values(this.value);
|
||||
let option = {
|
||||
grid: {
|
||||
left: '1%',
|
||||
right: '1%',
|
||||
top: '2%',
|
||||
bottom: '1%',
|
||||
containLabel: true
|
||||
},
|
||||
title: {
|
||||
text: this.text,
|
||||
subtext: this.subtext,
|
||||
x: 'center'
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{c}人',
|
||||
// position: ['30%', '90%'],
|
||||
position: 'top',
|
||||
backgroundColor: '#FAFBFE',
|
||||
textStyle: {
|
||||
fontSize: 14,
|
||||
color: '#6d6d6d'
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
// show: false,
|
||||
type: 'category',
|
||||
data: xAxisData,
|
||||
splitLine: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
// show: false,
|
||||
type: 'value',
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
// 设置刻度线粗度(粗的宽度)
|
||||
width: 1,
|
||||
// 颜色数组,数组数量要比刻度线数量大才能不循环使用
|
||||
color: [
|
||||
'rgba(0, 0, 0, 0)',
|
||||
'#eee',
|
||||
'#eee',
|
||||
'#eee',
|
||||
'#eee',
|
||||
'#eee',
|
||||
'#eee',
|
||||
'#eee',
|
||||
'#eee'
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
data: seriesData,
|
||||
type: 'bar',
|
||||
barWidth: 36,
|
||||
areaStyle: {
|
||||
normal: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: '#f2f5ff' },
|
||||
{ offset: 1, color: '#fff' }
|
||||
])
|
||||
}
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
barBorderRadius: [50],
|
||||
color: new echarts.graphic.LinearGradient(
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
[
|
||||
{
|
||||
offset: 0,
|
||||
color: '#3AA1FF' // 0% 处的颜色
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: '#36CBCB' // 100% 处的颜色
|
||||
}
|
||||
],
|
||||
false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
this.dom = echarts.init(this.$refs.dom, 'tdTheme');
|
||||
this.dom.setOption(option);
|
||||
on(window, 'resize', this.resize);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.bar-main {
|
||||
width: 100%;
|
||||
height: 360px;
|
||||
padding: 28px;
|
||||
background: #fff;
|
||||
}
|
||||
</style>
|
||||
106
smart-admin-web/src/views/home/components/chart-funnel.vue
Normal file
106
smart-admin-web/src/views/home/components/chart-funnel.vue
Normal file
@@ -0,0 +1,106 @@
|
||||
<template>
|
||||
<div class="funnel-main"
|
||||
id="box"
|
||||
ref="dom"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import echarts from 'echarts';
|
||||
import tdTheme from './theme.json';
|
||||
import { on, off } from '@/lib/util';
|
||||
echarts.registerTheme('tdTheme', tdTheme);
|
||||
export default {
|
||||
props: {
|
||||
value: Array,
|
||||
text: String,
|
||||
subtext: String
|
||||
},
|
||||
mounted() {
|
||||
this.initChart();
|
||||
},
|
||||
methods: {
|
||||
resize() {
|
||||
this.dom.resize();
|
||||
},
|
||||
initChart() {
|
||||
this.$nextTick(() => {
|
||||
let legend = this.value.map(_ => _.name);
|
||||
let option = {
|
||||
grid: {
|
||||
left: '1%',
|
||||
right: '1%',
|
||||
top: '2%',
|
||||
bottom: '1%',
|
||||
containLabel: true
|
||||
},
|
||||
title: {
|
||||
text: this.text,
|
||||
subtext: this.subtext,
|
||||
x: 'center'
|
||||
},
|
||||
tooltip: {
|
||||
show: false,
|
||||
trigger: 'item',
|
||||
formatter: '{c} ({d}%)',
|
||||
// position: ['30%', '90%'],
|
||||
position: 'right',
|
||||
backgroundColor: 'transparent',
|
||||
textStyle: {
|
||||
fontSize: 14,
|
||||
color: '#666'
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
left: 'right',
|
||||
bottom: 0,
|
||||
|
||||
// data: legend,
|
||||
backgroundColor: 'transparent',
|
||||
icon: 'circle'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '访问来源',
|
||||
type: 'funnel',
|
||||
radius: ['50%', '65%'],
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
normal: {
|
||||
show: false,
|
||||
position: 'right',
|
||||
formatter: '{c} ({d}%)'
|
||||
}
|
||||
},
|
||||
// labelLine: {
|
||||
// normal: {
|
||||
// show: false
|
||||
// }
|
||||
// },
|
||||
data: [
|
||||
{ value: 400, name: '交易完成' },
|
||||
{ value: 300, name: '支付订单' },
|
||||
{ value: 200, name: '生成订单' },
|
||||
{ value: 100, name: '放入购物车' },
|
||||
{ value: 100, name: '浏览网站' }
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
this.dom = echarts.init(this.$refs.dom, 'tdTheme');
|
||||
this.dom.setOption(option);
|
||||
on(window, 'resize', this.resize);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.funnel-main {
|
||||
width: 100%;
|
||||
height: 295px;
|
||||
padding: 28px;
|
||||
background: #fff;
|
||||
}
|
||||
</style>
|
||||
87
smart-admin-web/src/views/home/components/chart-gauge.vue
Normal file
87
smart-admin-web/src/views/home/components/chart-gauge.vue
Normal file
@@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<div class="gauge-main"
|
||||
id="box"
|
||||
ref="dom"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import echarts from 'echarts';
|
||||
import tdTheme from './theme.json';
|
||||
import { on, off } from '@/lib/util';
|
||||
echarts.registerTheme('tdTheme', tdTheme);
|
||||
export default {
|
||||
props: {
|
||||
value: Object,
|
||||
text: String,
|
||||
subtext: String
|
||||
},
|
||||
mounted () {
|
||||
this.initChart();
|
||||
},
|
||||
methods: {
|
||||
resize () {
|
||||
this.dom.resize();
|
||||
},
|
||||
initChart () {
|
||||
this.$nextTick(() => {
|
||||
let option = {
|
||||
grid: {
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom: 0
|
||||
// containLabel: true
|
||||
},
|
||||
tooltip: {
|
||||
formatter: '{a} <br/>{b} : {c}%'
|
||||
},
|
||||
toolbox: {},
|
||||
series: [
|
||||
{
|
||||
name: '业务指标',
|
||||
startAngle: 195,
|
||||
endAngle: -15,
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: [[0.6, '#4ECB73'], [0.8, '#FBD437'], [1, '#F47F92']],
|
||||
width: 16
|
||||
}
|
||||
},
|
||||
pointer: {
|
||||
length: '80%',
|
||||
width: 3,
|
||||
color: 'auto'
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
splitLine: { show: false },
|
||||
type: 'gauge',
|
||||
detail: {
|
||||
formatter: '{value}%',
|
||||
textStyle: {
|
||||
color: '#595959',
|
||||
fontSize: 32
|
||||
}
|
||||
},
|
||||
data: [{ value: 10 }]
|
||||
}
|
||||
]
|
||||
};
|
||||
this.dom = echarts.init(this.$refs.dom, 'tdTheme');
|
||||
this.dom.setOption(option);
|
||||
on(window, 'resize', this.resize);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.gauge-main {
|
||||
width: 100%;
|
||||
height: 360px;
|
||||
background: #fff;
|
||||
}
|
||||
</style>
|
||||
123
smart-admin-web/src/views/home/components/chart-line.vue
Normal file
123
smart-admin-web/src/views/home/components/chart-line.vue
Normal file
@@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<div class="line-main"
|
||||
id="box"
|
||||
ref="dom"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import echarts from 'echarts';
|
||||
import tdTheme from './theme.json';
|
||||
import { on, off } from '@/lib/util';
|
||||
echarts.registerTheme('tdTheme', tdTheme);
|
||||
export default {
|
||||
props: {
|
||||
value: Object,
|
||||
text: String,
|
||||
subtext: String
|
||||
},
|
||||
mounted() {
|
||||
this.initChart();
|
||||
},
|
||||
methods: {
|
||||
resize() {
|
||||
this.dom.resize();
|
||||
},
|
||||
initChart() {
|
||||
this.$nextTick(() => {
|
||||
let xAxisData = Object.keys(this.value);
|
||||
let seriesData = Object.values(this.value);
|
||||
let option = {
|
||||
grid: {
|
||||
left: '1%',
|
||||
right: '1%',
|
||||
top: '2%',
|
||||
bottom: '1%',
|
||||
containLabel: true
|
||||
},
|
||||
title: {
|
||||
text: this.text,
|
||||
subtext: this.subtext,
|
||||
x: 'center'
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{c}人',
|
||||
// position: ['30%', '90%'],
|
||||
position: 'top',
|
||||
backgroundColor: '#387DE1',
|
||||
textStyle: {
|
||||
fontSize: 18,
|
||||
color: '#fff'
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
// show: false,
|
||||
type: 'category',
|
||||
data: xAxisData,
|
||||
splitLine: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
// show: false,
|
||||
type: 'value',
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
// 设置刻度线粗度(粗的宽度)
|
||||
width: 1,
|
||||
// 颜色数组,数组数量要比刻度线数量大才能不循环使用
|
||||
color: [
|
||||
'rgba(0, 0, 0, 0)',
|
||||
'#eee',
|
||||
'#eee',
|
||||
'#eee',
|
||||
'#eee',
|
||||
'#eee',
|
||||
'#eee',
|
||||
'#eee',
|
||||
'#eee'
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
data: seriesData,
|
||||
type: 'line',
|
||||
areaStyle: {
|
||||
normal: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: '#f2f5ff' },
|
||||
{ offset: 1, color: '#fff' }
|
||||
])
|
||||
}
|
||||
},
|
||||
lineStyle: {
|
||||
normal: {
|
||||
width: 5,
|
||||
color: '#36CBCB'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
this.dom = echarts.init(this.$refs.dom, 'tdTheme');
|
||||
this.dom.setOption(option);
|
||||
on(window, 'resize', this.resize);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.line-main {
|
||||
width: 100%;
|
||||
height: 360px;
|
||||
padding: 28px;
|
||||
background: #fff;
|
||||
}
|
||||
</style>
|
||||
110
smart-admin-web/src/views/home/components/chart-pie.vue
Normal file
110
smart-admin-web/src/views/home/components/chart-pie.vue
Normal file
@@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<div class="pie-main"
|
||||
id="box"
|
||||
ref="dom"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import echarts from 'echarts';
|
||||
import tdTheme from './theme.json';
|
||||
import { on, off } from '@/lib/util';
|
||||
echarts.registerTheme('tdTheme', tdTheme);
|
||||
export default {
|
||||
props: {
|
||||
value: Array,
|
||||
text: String,
|
||||
subtext: String
|
||||
},
|
||||
mounted () {
|
||||
this.initChart();
|
||||
},
|
||||
methods: {
|
||||
resize () {
|
||||
this.dom.resize();
|
||||
},
|
||||
initChart () {
|
||||
this.$nextTick(() => {
|
||||
let legend = this.value.map(_ => _.name);
|
||||
let option = {
|
||||
title: {
|
||||
text: this.text,
|
||||
subtext: this.subtext,
|
||||
x: 'center'
|
||||
},
|
||||
position: {
|
||||
top: 40
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{c} ({d}%)',
|
||||
// position: ['30%', '90%'],
|
||||
position: function (point, params, dom, rect, size) {
|
||||
console.log(size);
|
||||
let leftWidth = size.viewSize[0] / 2 - size.contentSize[0] / 2;
|
||||
console.log(leftWidth);
|
||||
return { left: leftWidth, bottom: 0 };
|
||||
},
|
||||
backgroundColor: 'transparent',
|
||||
textStyle: {
|
||||
fontSize: 24,
|
||||
color: '#666'
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
// orient: 'vertical',
|
||||
top: 0,
|
||||
data: legend,
|
||||
backgroundColor: 'transparent',
|
||||
icon: 'circle'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '访问来源',
|
||||
type: 'pie',
|
||||
radius: ['45%', '60%'],
|
||||
center: ['50%', '52%'],
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
normal: {
|
||||
show: false,
|
||||
position: 'center'
|
||||
},
|
||||
emphasis: {
|
||||
show: true,
|
||||
textStyle: {
|
||||
fontSize: '24'
|
||||
}
|
||||
}
|
||||
},
|
||||
labelLine: {
|
||||
normal: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
data: [
|
||||
{ value: 335, name: '直接访问' },
|
||||
{ value: 310, name: '邮件营销' },
|
||||
{ value: 234, name: '联盟广告' },
|
||||
{ value: 135, name: '视频广告' },
|
||||
{ value: 1548, name: '搜索引擎' }
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
this.dom = echarts.init(this.$refs.dom, 'tdTheme');
|
||||
this.dom.setOption(option);
|
||||
on(window, 'resize', this.resize);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.pie-main {
|
||||
width: 100%;
|
||||
height: 360px;
|
||||
padding: 28px;
|
||||
background: #fff;
|
||||
}
|
||||
</style>
|
||||
41
smart-admin-web/src/views/home/components/home-circle.vue
Normal file
41
smart-admin-web/src/views/home/components/home-circle.vue
Normal file
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<div class="circle-main">
|
||||
<i-circle :percent="80"
|
||||
:size="164"
|
||||
:trail-width="1"
|
||||
stroke-color="#3AA1FF"
|
||||
stroke-linecap="round"
|
||||
trail-color="#ededed">
|
||||
<span class="demo-Circle-inner"
|
||||
style="font-size:24px">80%</span>
|
||||
</i-circle>
|
||||
<div>
|
||||
<button>查看详情</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.circle-main {
|
||||
background: #fff;
|
||||
height: 295px;
|
||||
text-align: center;
|
||||
padding-top: 20px;
|
||||
button {
|
||||
margin-top: 45px;
|
||||
width: 156px;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
height: 36px;
|
||||
background: rgba(241, 241, 241, 1);
|
||||
border-radius: 18px;
|
||||
color: #808080;
|
||||
font-size: 18px;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
59
smart-admin-web/src/views/home/components/home-progress.vue
Normal file
59
smart-admin-web/src/views/home/components/home-progress.vue
Normal file
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<div class="progress-list">
|
||||
<div :key="item.name"
|
||||
class="item"
|
||||
v-for="item in value">
|
||||
<p>
|
||||
<i :style="{background:item.color}"></i>
|
||||
{{item.name}}
|
||||
<span>{{item.value}}</span>
|
||||
</p>
|
||||
<Progress :percent="45"
|
||||
:stroke-color="item.color"
|
||||
:stroke-width="16"
|
||||
class="progress"
|
||||
hide-info
|
||||
status="active" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
value: Array
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.progress-list {
|
||||
height: 295px;
|
||||
padding: 28px;
|
||||
.item {
|
||||
display: flex;
|
||||
font-size: 16px;
|
||||
color: #595959;
|
||||
margin-bottom: 16px;
|
||||
span {
|
||||
color: #808080;
|
||||
margin: 0 29px;
|
||||
}
|
||||
p {
|
||||
width: 400px;
|
||||
i {
|
||||
display: inline-block;
|
||||
border-radius: 5px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-right: 13px;
|
||||
background: #f66;
|
||||
}
|
||||
padding-right: 200px;
|
||||
}
|
||||
.progress {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
490
smart-admin-web/src/views/home/components/theme.json
Normal file
490
smart-admin-web/src/views/home/components/theme.json
Normal file
@@ -0,0 +1,490 @@
|
||||
{
|
||||
"color": [
|
||||
"#2d8cf0",
|
||||
"#19be6b",
|
||||
"#ff9900",
|
||||
"#E46CBB",
|
||||
"#9A66E4",
|
||||
"#ed3f14"
|
||||
],
|
||||
"backgroundColor": "rgba(0,0,0,0)",
|
||||
"textStyle": {},
|
||||
"title": {
|
||||
"textStyle": {
|
||||
"color": "#516b91"
|
||||
},
|
||||
"subtextStyle": {
|
||||
"color": "#93b7e3"
|
||||
}
|
||||
},
|
||||
"line": {
|
||||
"itemStyle": {
|
||||
"normal": {
|
||||
"borderWidth": "2"
|
||||
}
|
||||
},
|
||||
"lineStyle": {
|
||||
"normal": {
|
||||
"width": "2"
|
||||
}
|
||||
},
|
||||
"symbolSize": "6",
|
||||
"symbol": "emptyCircle",
|
||||
"smooth": true
|
||||
},
|
||||
"radar": {
|
||||
"itemStyle": {
|
||||
"normal": {
|
||||
"borderWidth": "2"
|
||||
}
|
||||
},
|
||||
"lineStyle": {
|
||||
"normal": {
|
||||
"width": "2"
|
||||
}
|
||||
},
|
||||
"symbolSize": "6",
|
||||
"symbol": "emptyCircle",
|
||||
"smooth": true
|
||||
},
|
||||
"bar": {
|
||||
"itemStyle": {
|
||||
"normal": {
|
||||
"barBorderWidth": 0,
|
||||
"barBorderColor": "#ccc"
|
||||
},
|
||||
"emphasis": {
|
||||
"barBorderWidth": 0,
|
||||
"barBorderColor": "#ccc"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pie": {
|
||||
"itemStyle": {
|
||||
"normal": {
|
||||
"borderWidth": 0,
|
||||
"borderColor": "#ccc"
|
||||
},
|
||||
"emphasis": {
|
||||
"borderWidth": 0,
|
||||
"borderColor": "#ccc"
|
||||
}
|
||||
}
|
||||
},
|
||||
"scatter": {
|
||||
"itemStyle": {
|
||||
"normal": {
|
||||
"borderWidth": 0,
|
||||
"borderColor": "#ccc"
|
||||
},
|
||||
"emphasis": {
|
||||
"borderWidth": 0,
|
||||
"borderColor": "#ccc"
|
||||
}
|
||||
}
|
||||
},
|
||||
"boxplot": {
|
||||
"itemStyle": {
|
||||
"normal": {
|
||||
"borderWidth": 0,
|
||||
"borderColor": "#ccc"
|
||||
},
|
||||
"emphasis": {
|
||||
"borderWidth": 0,
|
||||
"borderColor": "#ccc"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parallel": {
|
||||
"itemStyle": {
|
||||
"normal": {
|
||||
"borderWidth": 0,
|
||||
"borderColor": "#ccc"
|
||||
},
|
||||
"emphasis": {
|
||||
"borderWidth": 0,
|
||||
"borderColor": "#ccc"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sankey": {
|
||||
"itemStyle": {
|
||||
"normal": {
|
||||
"borderWidth": 0,
|
||||
"borderColor": "#ccc"
|
||||
},
|
||||
"emphasis": {
|
||||
"borderWidth": 0,
|
||||
"borderColor": "#ccc"
|
||||
}
|
||||
}
|
||||
},
|
||||
"funnel": {
|
||||
"itemStyle": {
|
||||
"normal": {
|
||||
"borderWidth": 0,
|
||||
"borderColor": "#ccc"
|
||||
},
|
||||
"emphasis": {
|
||||
"borderWidth": 0,
|
||||
"borderColor": "#ccc"
|
||||
}
|
||||
}
|
||||
},
|
||||
"gauge": {
|
||||
"itemStyle": {
|
||||
"normal": {
|
||||
"borderWidth": 0,
|
||||
"borderColor": "#ccc"
|
||||
},
|
||||
"emphasis": {
|
||||
"borderWidth": 0,
|
||||
"borderColor": "#ccc"
|
||||
}
|
||||
}
|
||||
},
|
||||
"candlestick": {
|
||||
"itemStyle": {
|
||||
"normal": {
|
||||
"color": "#edafda",
|
||||
"color0": "transparent",
|
||||
"borderColor": "#d680bc",
|
||||
"borderColor0": "#8fd3e8",
|
||||
"borderWidth": "2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"graph": {
|
||||
"itemStyle": {
|
||||
"normal": {
|
||||
"borderWidth": 0,
|
||||
"borderColor": "#ccc"
|
||||
}
|
||||
},
|
||||
"lineStyle": {
|
||||
"normal": {
|
||||
"width": 1,
|
||||
"color": "#aaa"
|
||||
}
|
||||
},
|
||||
"symbolSize": "6",
|
||||
"symbol": "emptyCircle",
|
||||
"smooth": true,
|
||||
"color": [
|
||||
"#2d8cf0",
|
||||
"#19be6b",
|
||||
"#f5ae4a",
|
||||
"#9189d5",
|
||||
"#56cae2",
|
||||
"#cbb0e3"
|
||||
],
|
||||
"label": {
|
||||
"normal": {
|
||||
"textStyle": {
|
||||
"color": "#eee"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"map": {
|
||||
"itemStyle": {
|
||||
"normal": {
|
||||
"areaColor": "#f3f3f3",
|
||||
"borderColor": "#516b91",
|
||||
"borderWidth": 0.5
|
||||
},
|
||||
"emphasis": {
|
||||
"areaColor": "rgba(165,231,240,1)",
|
||||
"borderColor": "#516b91",
|
||||
"borderWidth": 1
|
||||
}
|
||||
},
|
||||
"label": {
|
||||
"normal": {
|
||||
"textStyle": {
|
||||
"color": "#000"
|
||||
}
|
||||
},
|
||||
"emphasis": {
|
||||
"textStyle": {
|
||||
"color": "rgb(81,107,145)"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"geo": {
|
||||
"itemStyle": {
|
||||
"normal": {
|
||||
"areaColor": "#f3f3f3",
|
||||
"borderColor": "#516b91",
|
||||
"borderWidth": 0.5
|
||||
},
|
||||
"emphasis": {
|
||||
"areaColor": "rgba(165,231,240,1)",
|
||||
"borderColor": "#516b91",
|
||||
"borderWidth": 1
|
||||
}
|
||||
},
|
||||
"label": {
|
||||
"normal": {
|
||||
"textStyle": {
|
||||
"color": "#000"
|
||||
}
|
||||
},
|
||||
"emphasis": {
|
||||
"textStyle": {
|
||||
"color": "rgb(81,107,145)"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"categoryAxis": {
|
||||
"axisLine": {
|
||||
"show": true,
|
||||
"lineStyle": {
|
||||
"color": "#cccccc"
|
||||
}
|
||||
},
|
||||
"axisTick": {
|
||||
"show": false,
|
||||
"lineStyle": {
|
||||
"color": "#333"
|
||||
}
|
||||
},
|
||||
"axisLabel": {
|
||||
"show": true,
|
||||
"textStyle": {
|
||||
"color": "#999999"
|
||||
}
|
||||
},
|
||||
"splitLine": {
|
||||
"show": true,
|
||||
"lineStyle": {
|
||||
"color": [
|
||||
"#eeeeee"
|
||||
]
|
||||
}
|
||||
},
|
||||
"splitArea": {
|
||||
"show": false,
|
||||
"areaStyle": {
|
||||
"color": [
|
||||
"rgba(250,250,250,0.05)",
|
||||
"rgba(200,200,200,0.02)"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"valueAxis": {
|
||||
"axisLine": {
|
||||
"show": true,
|
||||
"lineStyle": {
|
||||
"color": "#cccccc"
|
||||
}
|
||||
},
|
||||
"axisTick": {
|
||||
"show": false,
|
||||
"lineStyle": {
|
||||
"color": "#333"
|
||||
}
|
||||
},
|
||||
"axisLabel": {
|
||||
"show": true,
|
||||
"textStyle": {
|
||||
"color": "#999999"
|
||||
}
|
||||
},
|
||||
"splitLine": {
|
||||
"show": true,
|
||||
"lineStyle": {
|
||||
"color": [
|
||||
"#eeeeee"
|
||||
]
|
||||
}
|
||||
},
|
||||
"splitArea": {
|
||||
"show": false,
|
||||
"areaStyle": {
|
||||
"color": [
|
||||
"rgba(250,250,250,0.05)",
|
||||
"rgba(200,200,200,0.02)"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"logAxis": {
|
||||
"axisLine": {
|
||||
"show": true,
|
||||
"lineStyle": {
|
||||
"color": "#cccccc"
|
||||
}
|
||||
},
|
||||
"axisTick": {
|
||||
"show": false,
|
||||
"lineStyle": {
|
||||
"color": "#333"
|
||||
}
|
||||
},
|
||||
"axisLabel": {
|
||||
"show": true,
|
||||
"textStyle": {
|
||||
"color": "#999999"
|
||||
}
|
||||
},
|
||||
"splitLine": {
|
||||
"show": true,
|
||||
"lineStyle": {
|
||||
"color": [
|
||||
"#eeeeee"
|
||||
]
|
||||
}
|
||||
},
|
||||
"splitArea": {
|
||||
"show": false,
|
||||
"areaStyle": {
|
||||
"color": [
|
||||
"rgba(250,250,250,0.05)",
|
||||
"rgba(200,200,200,0.02)"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"timeAxis": {
|
||||
"axisLine": {
|
||||
"show": true,
|
||||
"lineStyle": {
|
||||
"color": "#cccccc"
|
||||
}
|
||||
},
|
||||
"axisTick": {
|
||||
"show": false,
|
||||
"lineStyle": {
|
||||
"color": "#333"
|
||||
}
|
||||
},
|
||||
"axisLabel": {
|
||||
"show": true,
|
||||
"textStyle": {
|
||||
"color": "#999999"
|
||||
}
|
||||
},
|
||||
"splitLine": {
|
||||
"show": true,
|
||||
"lineStyle": {
|
||||
"color": [
|
||||
"#eeeeee"
|
||||
]
|
||||
}
|
||||
},
|
||||
"splitArea": {
|
||||
"show": false,
|
||||
"areaStyle": {
|
||||
"color": [
|
||||
"rgba(250,250,250,0.05)",
|
||||
"rgba(200,200,200,0.02)"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"toolbox": {
|
||||
"iconStyle": {
|
||||
"normal": {
|
||||
"borderColor": "#999"
|
||||
},
|
||||
"emphasis": {
|
||||
"borderColor": "#666"
|
||||
}
|
||||
}
|
||||
},
|
||||
"legend": {
|
||||
"textStyle": {
|
||||
"color": "#999999"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"axisPointer": {
|
||||
"lineStyle": {
|
||||
"color": "#ccc",
|
||||
"width": 1
|
||||
},
|
||||
"crossStyle": {
|
||||
"color": "#ccc",
|
||||
"width": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"timeline": {
|
||||
"lineStyle": {
|
||||
"color": "#8fd3e8",
|
||||
"width": 1
|
||||
},
|
||||
"itemStyle": {
|
||||
"normal": {
|
||||
"color": "#8fd3e8",
|
||||
"borderWidth": 1
|
||||
},
|
||||
"emphasis": {
|
||||
"color": "#8fd3e8"
|
||||
}
|
||||
},
|
||||
"controlStyle": {
|
||||
"normal": {
|
||||
"color": "#8fd3e8",
|
||||
"borderColor": "#8fd3e8",
|
||||
"borderWidth": 0.5
|
||||
},
|
||||
"emphasis": {
|
||||
"color": "#8fd3e8",
|
||||
"borderColor": "#8fd3e8",
|
||||
"borderWidth": 0.5
|
||||
}
|
||||
},
|
||||
"checkpointStyle": {
|
||||
"color": "#8fd3e8",
|
||||
"borderColor": "rgba(138,124,168,0.37)"
|
||||
},
|
||||
"label": {
|
||||
"normal": {
|
||||
"textStyle": {
|
||||
"color": "#8fd3e8"
|
||||
}
|
||||
},
|
||||
"emphasis": {
|
||||
"textStyle": {
|
||||
"color": "#8fd3e8"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"visualMap": {
|
||||
"color": [
|
||||
"#516b91",
|
||||
"#59c4e6",
|
||||
"#a5e7f0"
|
||||
]
|
||||
},
|
||||
"dataZoom": {
|
||||
"backgroundColor": "rgba(0,0,0,0)",
|
||||
"dataBackgroundColor": "rgba(255,255,255,0.3)",
|
||||
"fillerColor": "rgba(167,183,204,0.4)",
|
||||
"handleColor": "#a7b7cc",
|
||||
"handleSize": "100%",
|
||||
"textStyle": {
|
||||
"color": "#333"
|
||||
}
|
||||
},
|
||||
"markPoint": {
|
||||
"label": {
|
||||
"normal": {
|
||||
"textStyle": {
|
||||
"color": "#eee"
|
||||
}
|
||||
},
|
||||
"emphasis": {
|
||||
"textStyle": {
|
||||
"color": "#eee"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
154
smart-admin-web/src/views/home/home.vue
Normal file
154
smart-admin-web/src/views/home/home.vue
Normal file
@@ -0,0 +1,154 @@
|
||||
<template>
|
||||
<div>
|
||||
<Row>
|
||||
<Col>
|
||||
<HomeCard desc="Pending transaction" title="用户活跃量">
|
||||
<ActivePlate :infoList="infoCardData" />
|
||||
</HomeCard>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row :gutter="20">
|
||||
<i-col :lg="6" :md="24">
|
||||
<HomeCard desc="User from" title="用户来源">
|
||||
<ChartPie :value="pieData" />
|
||||
</HomeCard>
|
||||
</i-col>
|
||||
<i-col :lg="18" :md="24">
|
||||
<HomeCard desc="User active" title="每周用户活跃量">
|
||||
<ChartLine :value="lineData" />
|
||||
</HomeCard>
|
||||
</i-col>
|
||||
</Row>
|
||||
<Row :gutter="20">
|
||||
<i-col :lg="18" :md="24">
|
||||
<HomeCard desc="User from" title="柱状图">
|
||||
<ChartBar :value="lineData" />
|
||||
</HomeCard>
|
||||
</i-col>
|
||||
<i-col :lg="6" :md="24">
|
||||
<HomeCard desc="complete" title="完成率">
|
||||
<ChartGauge />
|
||||
</HomeCard>
|
||||
</i-col>
|
||||
</Row>
|
||||
<Row :gutter="20">
|
||||
<i-col :lg="12" :md="24">
|
||||
<HomeCard desc="progress" title="进度条">
|
||||
<HomeProgress :value="pieData" />
|
||||
</HomeCard>
|
||||
</i-col>
|
||||
<i-col :lg="6" :md="24">
|
||||
<HomeCard desc="progress" title="目标完成度">
|
||||
<Home-circle />
|
||||
</HomeCard>
|
||||
</i-col>
|
||||
<i-col :lg="6" :md="24">
|
||||
<HomeCard desc="progress" title="漏斗图">
|
||||
<ChartFunnel :value="pieData" />
|
||||
</HomeCard>
|
||||
</i-col>
|
||||
</Row>
|
||||
|
||||
|
||||
<Modal
|
||||
v-model="adModal" width="800">
|
||||
<Ad/>
|
||||
</Modal>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ActivePlate from '_c/active-plate/active-plate';
|
||||
import CountTo from '_c/count-to';
|
||||
import HomeCard from './components/card';
|
||||
import ChartPie from './components/chart-pie';
|
||||
import ChartLine from './components/chart-line';
|
||||
import ChartGauge from './components/chart-gauge';
|
||||
import ChartBar from './components/chart-bar';
|
||||
import HomeCircle from './components/home-circle';
|
||||
import HomeProgress from './components/home-progress';
|
||||
import ChartFunnel from './components/chart-funnel';
|
||||
import Ad from '@/components/smart-admin-ad';
|
||||
|
||||
export default {
|
||||
name: 'Home',
|
||||
components: {
|
||||
HomeCard,
|
||||
ActivePlate,
|
||||
CountTo,
|
||||
ChartPie,
|
||||
ChartFunnel,
|
||||
ChartLine,
|
||||
HomeCircle,
|
||||
ChartGauge,
|
||||
ChartBar,
|
||||
HomeProgress,
|
||||
Ad
|
||||
},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
adModal:true,
|
||||
infoCardData: [
|
||||
{
|
||||
title: '新增用户',
|
||||
icon: 'md-person-add',
|
||||
count: 803,
|
||||
color: '#11A0F8'
|
||||
},
|
||||
{ title: '累计点击', icon: 'md-locate', count: 232, color: '#FFBB44 ' },
|
||||
{
|
||||
title: '新增问答',
|
||||
icon: 'md-help-circle',
|
||||
count: 142,
|
||||
color: '#7ACE4C'
|
||||
},
|
||||
{ title: '分享统计', icon: 'md-share', count: 657, color: '#11A0F8' },
|
||||
{
|
||||
title: '新增互动',
|
||||
icon: 'md-chatbubbles',
|
||||
count: 12,
|
||||
color: '#91AFC8'
|
||||
},
|
||||
{ title: '新增页面', icon: 'md-map', count: 14, color: '#91AFC8' }
|
||||
],
|
||||
pieData: [
|
||||
{ value: 335, name: '直接访问', color: '#3AA1FF' },
|
||||
{ value: 310, name: '邮件营销', color: '#36CBCB' },
|
||||
{ value: 234, name: '联盟广告', color: '#4ECB73' },
|
||||
{ value: 135, name: '视频广告', color: '#F47F92' },
|
||||
{ value: 1548, name: '搜索引擎', color: '#FBD437' }
|
||||
],
|
||||
lineData: {
|
||||
Mon: 13253,
|
||||
Tue: 34235,
|
||||
Wed: 26321,
|
||||
Thu: 12340,
|
||||
Fri: 24643,
|
||||
Sat: 1322,
|
||||
Sun: 1324
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
filters: {},
|
||||
created() {},
|
||||
mounted() {},
|
||||
beforeCreate() {},
|
||||
beforeMount() {},
|
||||
beforeUpdate() {},
|
||||
updated() {},
|
||||
beforeDestroy() {},
|
||||
destroyed() {},
|
||||
activated() {},
|
||||
methods: {}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.count-style {
|
||||
font-size: 50px;
|
||||
}
|
||||
</style>
|
||||
2
smart-admin-web/src/views/home/index.js
Normal file
2
smart-admin-web/src/views/home/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import home from './home.vue';
|
||||
export default home;
|
||||
94
smart-admin-web/src/views/keep-alive/add-content.vue
Normal file
94
smart-admin-web/src/views/keep-alive/add-content.vue
Normal file
@@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<Card class="warp-card" dis-hover>
|
||||
<Alert>
|
||||
<h3>让我们测试一下</h3>
|
||||
<pre>
|
||||
1 Query保存 之后,刷新KeepAlive页面,即router query传入noKeepAlive=true参数
|
||||
2 Param保存 之后,刷新KeepAlive页面,即router param传入noKeepAlive=true参数
|
||||
3 返回 之后,不刷新KeepAlive页面,不用传入任何参数
|
||||
</pre>
|
||||
</Alert>
|
||||
<Form class="tools" inline>
|
||||
<FormItem>
|
||||
<Input placeholder="请输入" v-model="addData" />
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button @click="addContent4Query" type="primary">Query保存</Button>
|
||||
<Button @click="addContent4Param" style="margin-left:10px" type="primary">Param保存</Button>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button @click="backPage" type="default">返回</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'KeepAliveAddContent',
|
||||
components: {},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
addData: ''
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
filters: {},
|
||||
methods: {
|
||||
addContent4Query() {
|
||||
if (this.addData === '') {
|
||||
this.$Message.error('请输入内容');
|
||||
return;
|
||||
}
|
||||
|
||||
this.$Notice.success({
|
||||
title: 'noKeepAlive跳转',
|
||||
render: h => {
|
||||
return h('pre', [
|
||||
'this.$router.closeCurrentPageAndPush({\r\n' +
|
||||
' name: "KeepAliveContentList",\r\n' +
|
||||
' query: { noKeepAlive: true }\r\n' +
|
||||
'});'
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
this.$router.closeCurrentPageAndPush({
|
||||
name: 'KeepAliveContentList',
|
||||
query: { noKeepAlive: true }
|
||||
});
|
||||
},
|
||||
addContent4Param() {
|
||||
if (this.addData === '') {
|
||||
this.$Message.error('请输入内容');
|
||||
return;
|
||||
}
|
||||
|
||||
this.$Notice.success({
|
||||
title: 'noKeepAlive跳转',
|
||||
render: h => {
|
||||
return h('pre', [
|
||||
'this.$router.closeCurrentPageAndPush({\r\n' +
|
||||
' name: "KeepAliveContentList",\r\n' +
|
||||
' params: { noKeepAlive: true }\r\n' +
|
||||
'});'
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
this.$router.closeCurrentPageAndPush({
|
||||
name: 'KeepAliveContentList',
|
||||
params: { noKeepAlive: true }
|
||||
});
|
||||
},
|
||||
backPage() {
|
||||
// 返回
|
||||
this.$router.closeCurrentPage();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
</style>
|
||||
80
smart-admin-web/src/views/keep-alive/content-list.vue
Normal file
80
smart-admin-web/src/views/keep-alive/content-list.vue
Normal file
@@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<Card class="warp-card" dis-hover>
|
||||
<Alert>
|
||||
<h3>keep-alive介绍:</h3>
|
||||
<pre>
|
||||
简介:我们修改了原版iview-admin缓存策略,使之更灵活
|
||||
|
||||
用途:
|
||||
· 用于关闭页面后跳转指定页面,可控制是否刷新跳转页面
|
||||
· 点击左侧菜单栏打开已有页面,标签页切换依旧会缓存
|
||||
</pre>
|
||||
</Alert>
|
||||
<Form class="tools" inline>
|
||||
<FormItem>
|
||||
<Input placeholder="请输入" v-model="searchString">
|
||||
<Button @click="searchContent" icon="ios-search" slot="append"></Button>
|
||||
</Input>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button @click="addContent" icon="md-add" type="primary">添加</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<Table :columns="columns" :data="tableData" border></Table>
|
||||
</Card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'KeepAliveContentList',
|
||||
components: {},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
sourceData: [
|
||||
{ name: '张三' },
|
||||
{ name: '李四' },
|
||||
{ name: '王二' },
|
||||
{ name: '唐三' },
|
||||
{ name: '赵大' },
|
||||
{ name: '李二' }
|
||||
],
|
||||
columns: [
|
||||
{
|
||||
title: '名称',
|
||||
key: 'name'
|
||||
}
|
||||
],
|
||||
tableData: [],
|
||||
searchString: ''
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
if (this.$route.query.data) {
|
||||
this.sourceData = [{ name: this.$route.query.data }, ...this.sourceData];
|
||||
}
|
||||
this.searchContent();
|
||||
},
|
||||
methods: {
|
||||
searchContent() {
|
||||
this.tableData = [];
|
||||
this.sourceData.forEach(val => {
|
||||
if (
|
||||
val.name.indexOf(this.searchString) !== -1 ||
|
||||
this.searchString == ''
|
||||
) {
|
||||
this.tableData.push(val);
|
||||
}
|
||||
});
|
||||
},
|
||||
addContent() {
|
||||
this.$router.push({
|
||||
path: '/keep-alive/add-content',
|
||||
query: {}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
</style>
|
||||
289
smart-admin-web/src/views/login/canvas.js
Normal file
289
smart-admin-web/src/views/login/canvas.js
Normal file
@@ -0,0 +1,289 @@
|
||||
// 离子波浪
|
||||
export const lonWave = () => {
|
||||
var starlings = function (n, r, t, o, e, u, i, f) {
|
||||
var a = f.onSetup
|
||||
void 0 === a && (a = null)
|
||||
var v = f.onRepeat
|
||||
void 0 === v && (v = null)
|
||||
var c = f.modifier
|
||||
void 0 === c && (c = null)
|
||||
var l = f.perspective
|
||||
void 0 === l && (l = 1)
|
||||
var d = f.pixelRatio
|
||||
void 0 === d && (d = 1)
|
||||
var m = f.triangles
|
||||
void 0 === m && (m = !1)
|
||||
var s
|
||||
var p
|
||||
var y = r.length
|
||||
var w = function (n, r) {
|
||||
let t = s.createShader(n)
|
||||
return s.shaderSource(t, r), s.compileShader(t), t
|
||||
}
|
||||
var b = function () {
|
||||
for (var n = 0; n < o.length; n += 1) {
|
||||
for (var r = s.createBuffer(), e = o[n], u = e.data(0, 0).length, i = new Float32Array(t * y * u), f = 0; f < t; f += 1) {
|
||||
for (var a = e.data(f, t), v = f * y * u, l = 0; l < y; l += 1) {
|
||||
for (var d = 0; d < u; d += 1) {
|
||||
c !== null && e.name === c.attribute ? i[v] = c.value(i[v], a, d, l) : i[v] = a[d]
|
||||
v += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
s.bindBuffer(s.ARRAY_BUFFER, r)
|
||||
s.bufferData(s.ARRAY_BUFFER, i, s.STATIC_DRAW)
|
||||
var m = s.getAttribLocation(p, o[n].name)
|
||||
s.enableVertexAttribArray(m)
|
||||
s.vertexAttribPointer(m, u, s.FLOAT, !1, !1, 0, 0)
|
||||
}
|
||||
}
|
||||
var A = function () {
|
||||
e.push({
|
||||
name: 'uMVP',
|
||||
type: 'mat4'
|
||||
})
|
||||
for (var n = 0; n < e.length; n += 1) {
|
||||
var r = s.getUniformLocation(p, e[n].name)
|
||||
e[n].location = r
|
||||
}
|
||||
}
|
||||
var F = {
|
||||
float: function (n, r) {
|
||||
return s.uniform1f(n, r)
|
||||
},
|
||||
vec2: function (n, r) {
|
||||
return s.uniform2fv(n, r)
|
||||
},
|
||||
vec3: function (n, r) {
|
||||
return s.uniform3fv(n, r)
|
||||
},
|
||||
vec4: function (n, r) {
|
||||
return s.uniform4fv(n, r)
|
||||
},
|
||||
mat2: function (n, r) {
|
||||
return s.uniformMatrix2fv(n, !1, r)
|
||||
},
|
||||
mat3: function (n, r) {
|
||||
return s.uniformMatrix3fv(n, !1, r)
|
||||
},
|
||||
mat4: function (n, r) {
|
||||
return s.uniformMatrix4fv(n, !1, r)
|
||||
}
|
||||
}
|
||||
var g = function () {
|
||||
s.clear(16640)
|
||||
s.useProgram(p)
|
||||
v !== null && v(s, p, e)
|
||||
for (var n = 0; n < e.length; n += 1) F[e[n].type](e[n].location, e[n].value)
|
||||
s.drawArrays(m ? s.TRIANGLES : s.POINTS, 0, y * t)
|
||||
requestAnimationFrame(g)
|
||||
}
|
||||
var h = function () {
|
||||
n.width = n.clientWidth * d
|
||||
n.height = n.clientHeight * d
|
||||
var r = s.drawingBufferWidth
|
||||
var t = s.drawingBufferHeight
|
||||
s.viewport(0, 0, r, t)
|
||||
e[e.length - 1].value = [l / (r / t), 0, 0, 0, 0, l, 0, 0, 0, 0, -1, -1, 0, 0, 1, 1]
|
||||
}
|
||||
s = n.getContext('webgl')
|
||||
p = s.createProgram()
|
||||
s.attachShader(p, w(s.VERTEX_SHADER, u))
|
||||
s.attachShader(p, w(s.FRAGMENT_SHADER, i))
|
||||
s.linkProgram(p)
|
||||
A()
|
||||
h()
|
||||
b()
|
||||
a !== null && a(s)
|
||||
g()
|
||||
window.addEventListener('resize', h, !1)
|
||||
}
|
||||
|
||||
// Do you like rainbow waves?
|
||||
var rainbow = false
|
||||
|
||||
// Need more performance?
|
||||
var HD = true
|
||||
|
||||
var canvas = document.getElementById('canvas')
|
||||
var background = document.querySelector('.background')
|
||||
var bar = document.querySelector('.progress')
|
||||
var initialize = function initialize (vertices) {
|
||||
var pixelRatio = HD ? window.devicePixelRatio : 1
|
||||
var rows = HD ? 90 : 90
|
||||
var multiplier = rows * rows
|
||||
var duration = 0.4
|
||||
var geometry = [{
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
}]
|
||||
var pointSize = (HD ? 6 : 2).toFixed(1)
|
||||
|
||||
var step = 0.004
|
||||
var size = 5
|
||||
var attributes = [{
|
||||
name: 'aPositionStart',
|
||||
data: function data (i, total) {
|
||||
return [size - (i % rows / rows + 0.5 / rows) * (size * 2), -1, (size - (Math.floor(i / rows) / rows + 0.5 / rows) * size * 2) * -1]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'aControlPointOne',
|
||||
data: function data (i) {
|
||||
return [size - (i % rows / rows + 0.5 / rows) * (size * 2), -0.5 + getRandom(0.2), (size - (Math.floor(i / rows) / rows + 0.5 / rows) * size * 2) * -1]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'aControlPointTwo',
|
||||
data: function data (i) {
|
||||
return [size - (i % rows / rows + 0.5 / rows) * (size * 2), -0.5 + getRandom(0.2), (size - (Math.floor(i / rows) / rows + 0.5 / rows) * size * 2) * -1]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'aPositionEnd',
|
||||
data: function data (i) {
|
||||
return [size - (i % rows / rows + 0.5 / rows) * (size * 2), -1, (size - (Math.floor(i / rows) / rows + 0.5 / rows) * size * 2) * -1]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'aOffset',
|
||||
data: function data (i) {
|
||||
return [i * ((1 - duration) / (multiplier - 1))]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'aColor',
|
||||
data: function data (i, total) {
|
||||
return getHSL(rainbow ? i / total * 1.0 : 0.5 + i / total * 0.4, 0.5, 0.5)
|
||||
}
|
||||
}]
|
||||
|
||||
var uniforms = [{
|
||||
name: 'uProgress',
|
||||
type: 'float',
|
||||
value: 0.8
|
||||
}]
|
||||
|
||||
var vertexShader = '\n attribute vec3 aPositionStart;\n attribute vec3 aControlPointOne;\n attribute vec3 aControlPointTwo;\n attribute vec3 aPositionEnd;\n attribute float aOffset;\n attribute vec3 aColor;\n\n uniform float uProgress;\n uniform mat4 uMVP;\n\n varying vec3 vColor;\n\n vec3 bezier4(vec3 a, vec3 b, vec3 c, vec3 d, float t) {\n return mix(mix(mix(a, b, t), mix(b, c, t), t), mix(mix(b, c, t), mix(c, d, t), t), t);\n }\n\n float easeInOutQuint(float t){\n return t < 0.5 ? 16.0 * t * t * t * t * t : 1.0 + 16.0 * (--t) * t * t * t * t;\n }\n\n void main () {\n float tProgress = easeInOutQuint(min(1.0, max(0.0, (uProgress - aOffset)) / ' + duration + '));\n vec3 newPosition = bezier4(aPositionStart, aControlPointOne, aControlPointTwo, aPositionEnd, tProgress);\n gl_PointSize = ' + pointSize + ' + ((newPosition.y + 1.0) * 80.0);\n gl_Position = uMVP * vec4(newPosition, 1.0);\n vColor = aColor;\n }\n'
|
||||
|
||||
var fragmentShader = '\n precision mediump float;\n\n varying vec3 vColor;\n\n void main() {\n vec2 pc = 2.0 * gl_PointCoord - 1.0;\n gl_FragColor = vec4(vColor, 1.0 - dot(pc, pc));\n }\n'
|
||||
|
||||
var onSetup = function onSetup (gl) {
|
||||
gl.blendFunc(gl.SRC_ALPHA, gl.ONE)
|
||||
gl.enable(gl.BLEND)
|
||||
}
|
||||
|
||||
var onRepeat = function onRepeat () {
|
||||
rotateY(uniforms[uniforms.length - 1].value, 0.002)
|
||||
if (uniforms[0].value < 0) {
|
||||
uniforms[0].value = 1
|
||||
}
|
||||
uniforms[0].value -= step
|
||||
}
|
||||
|
||||
var options = {
|
||||
onSetup: onSetup,
|
||||
onRepeat: onRepeat,
|
||||
pixelRatio: pixelRatio
|
||||
}
|
||||
|
||||
starlings(canvas, geometry, multiplier, attributes, uniforms, vertexShader, fragmentShader, options)
|
||||
}
|
||||
|
||||
var getRandom = function getRandom (value) {
|
||||
return Math.random() * value - value / 2
|
||||
}
|
||||
|
||||
var rotateY = function rotateY (matrix, angle) {
|
||||
var sin = Math.sin(angle)
|
||||
var cos = Math.cos(angle)
|
||||
var clone = JSON.parse(JSON.stringify(matrix))
|
||||
|
||||
matrix[0] = clone[0] * cos - clone[8] * sin
|
||||
matrix[1] = clone[1] * cos - clone[9] * sin
|
||||
matrix[2] = clone[2] * cos - clone[10] * sin
|
||||
matrix[3] = clone[3] * cos - clone[11] * sin
|
||||
matrix[8] = clone[0] * sin + clone[8] * cos
|
||||
matrix[9] = clone[1] * sin + clone[9] * cos
|
||||
matrix[10] = clone[2] * sin + clone[10] * cos
|
||||
matrix[11] = clone[3] * sin + clone[11] * cos
|
||||
}
|
||||
|
||||
var h2r = function h2r (p, q, t) {
|
||||
if (t < 0) t += 1
|
||||
if (t > 1) t -= 1
|
||||
if (t < 1 / 6) return p + (q - p) * 6 * t
|
||||
if (t < 1 / 2) return q
|
||||
if (t < 2 / 3) return p + (q - p) * 6 * (2 / 3 - t)
|
||||
return p
|
||||
}
|
||||
|
||||
var getHSL = function getHSL (h, s, l) {
|
||||
h = (h % 1 + 1) % 1
|
||||
s = Math.max(0, Math.min(1, s))
|
||||
l = Math.max(0, Math.min(1, l))
|
||||
if (s === 0) return [l, l, l]
|
||||
var p = l <= 0.5 ? l * (1 + s) : l + s - l * s
|
||||
var q = 2 * l - p
|
||||
return [h2r(q, p, h + 1 / 3), h2r(q, p, h), h2r(q, p, h - 1 / 3)]
|
||||
}
|
||||
initialize()
|
||||
}
|
||||
|
||||
// 随机线条
|
||||
export const canvasParticle = (function () {
|
||||
function getElementByTag (name) { return document.getElementsByTagName(name) }
|
||||
function getELementById (id) { return document.getElementById(id) }
|
||||
function canvasInit (canvasConfig) {
|
||||
canvasConfig = canvasConfig || {}
|
||||
var html = getElementByTag('html')[0]
|
||||
var body = document.getElementById('canvasView')
|
||||
var canvasObj = document.createElement('canvas')
|
||||
var canvas = { element: canvasObj, points: [], config: { vx: canvasConfig.vx || 4, vy: canvasConfig.vy || 4, height: canvasConfig.height || 2, width: canvasConfig.width || 2, count: canvasConfig.count || 100, color: canvasConfig.color || '121, 162, 185', stroke: canvasConfig.stroke || '130,255,255', dist: canvasConfig.dist || 6000, e_dist: canvasConfig.e_dist || 20000, max_conn: 10 } }; if (canvas.element.getContext('2d')) { canvas.context = canvas.element.getContext('2d') } else { return null }
|
||||
body.style.padding = '0'; body.style.margin = '0'; body.appendChild(canvas.element); canvas.element.style = 'position: fixed; top: 0; left: 0; z-index: -1;'; canvasSize(canvas.element); window.onresize = function () { canvasSize(canvas.element) }
|
||||
body.onmousemove = function (e) { var event = e || window.event; canvas.mouse = { x: event.clientX, y: event.clientY } }
|
||||
document.onmouseleave = function () { canvas.mouse = undefined }
|
||||
setInterval(function () { drawPoint(canvas) }, 40)
|
||||
}
|
||||
function canvasSize (canvas) {
|
||||
var width = document.getElementById('canvasView').style.width
|
||||
var height = document.getElementById('canvasView').style.height
|
||||
width = parseInt(width); height = parseInt(height)
|
||||
canvas.width = width || window.innerWeight || document.documentElement.clientWidth || document.body.clientWidth; canvas.height = height || window.innerWeight || document.documentElement.clientHeight || document.body.clientHeight
|
||||
}
|
||||
function drawPoint (canvas) {
|
||||
var context = canvas.context
|
||||
var point
|
||||
var dist
|
||||
context.clearRect(0, 0, canvas.element.width, canvas.element.height); context.beginPath(); context.fillStyle = 'rgb(' + canvas.config.color + ')'; for (var i = 0, len = canvas.config.count; i < len; i++) {
|
||||
if (canvas.points.length != canvas.config.count) { point = { x: Math.floor(Math.random() * canvas.element.width), y: Math.floor(Math.random() * canvas.element.height), vx: canvas.config.vx / 2 - Math.random() * canvas.config.vx, vy: canvas.config.vy / 2 - Math.random() * canvas.config.vy } } else { point = borderPoint(canvas.points[i], canvas) }
|
||||
context.fillRect(point.x - canvas.config.width / 2, point.y - canvas.config.height / 2, canvas.config.width, canvas.config.height); canvas.points[i] = point
|
||||
}
|
||||
drawLine(context, canvas, canvas.mouse); context.closePath()
|
||||
}
|
||||
function borderPoint (point, canvas) {
|
||||
var p = point; if (point.x <= 0 || point.x >= canvas.element.width) { p.vx = -p.vx; p.x += p.vx } else if (point.y <= 0 || point.y >= canvas.element.height) { p.vy = -p.vy; p.y += p.vy } else { p = { x: p.x + p.vx, y: p.y + p.vy, vx: p.vx, vy: p.vy } }
|
||||
return p
|
||||
}
|
||||
function drawLine (context, canvas, mouse) {
|
||||
let dist
|
||||
context = context || canvas.context; for (var i = 0, len = canvas.config.count; i < len; i++) {
|
||||
canvas.points[i].max_conn = 0; for (var j = 0; j < len; j++) {
|
||||
if (i != j) {
|
||||
dist = Math.round(canvas.points[i].x - canvas.points[j].x) * Math.round(canvas.points[i].x - canvas.points[j].x) +
|
||||
Math.round(canvas.points[i].y - canvas.points[j].y) * Math.round(canvas.points[i].y - canvas.points[j].y); if (dist <= canvas.config.dist && canvas.points[i].max_conn < canvas.config.max_conn) {
|
||||
canvas.points[i].max_conn++; context.lineWidth = 0.5 - dist / canvas.config.dist; context.strokeStyle = 'rgba(' + canvas.config.stroke + ',' + (1 - dist / canvas.config.dist) + ')'
|
||||
context.beginPath(); context.moveTo(canvas.points[i].x, canvas.points[i].y); context.lineTo(canvas.points[j].x, canvas.points[j].y); context.stroke()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mouse) {
|
||||
dist = Math.round(canvas.points[i].x - mouse.x) * Math.round(canvas.points[i].x - mouse.x) +
|
||||
Math.round(canvas.points[i].y - mouse.y) * Math.round(canvas.points[i].y - mouse.y); if (dist > canvas.config.dist && dist <= canvas.config.e_dist) { canvas.points[i].x = canvas.points[i].x + (mouse.x - canvas.points[i].x) / 20; canvas.points[i].y = canvas.points[i].y + (mouse.y - canvas.points[i].y) / 20 }
|
||||
if (dist <= canvas.config.e_dist) { context.lineWidth = 1; context.strokeStyle = 'rgba(' + canvas.config.stroke + ',' + (1 - dist / canvas.config.e_dist) + ')'; context.beginPath(); context.moveTo(canvas.points[i].x, canvas.points[i].y); context.lineTo(mouse.x, mouse.y); context.stroke() }
|
||||
}
|
||||
}
|
||||
}
|
||||
return canvasInit
|
||||
})()
|
||||
133
smart-admin-web/src/views/login/components/login-form.vue
Normal file
133
smart-admin-web/src/views/login/components/login-form.vue
Normal file
@@ -0,0 +1,133 @@
|
||||
<template>
|
||||
<div>
|
||||
<Form :model="formData" :rules="rules" @keydown.enter.native="login" ref="loginForm">
|
||||
<FormItem prop="loginName">
|
||||
<Input placeholder="请输入用户名" v-model="formData.loginName"></Input>
|
||||
</FormItem>
|
||||
<FormItem prop="loginPwd">
|
||||
<Input placeholder="请输入密码" type="password" v-model="formData.loginPwd"></Input>
|
||||
</FormItem>
|
||||
<FormItem prop="code">
|
||||
<Input class="code-input" placeholder="请输入验证码" v-model="formData.code"></Input>
|
||||
<img :src="codeUrl" @click="verificationCode" class="codeUrl" v-if="codeUrl" />
|
||||
</FormItem>
|
||||
<FormItem class="remember">
|
||||
<Checkbox>记住密码</Checkbox>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button :loading="btnLoading" @click="login" long type="primary">登录</Button>
|
||||
</FormItem>
|
||||
<div class="other-way">
|
||||
<p class="inline" style="float:left">其他方式登陆</p>
|
||||
<div class="inline align" style="float:right">
|
||||
<img alt class="marginLeft" src="../../../assets/images/login-taobao.png" />
|
||||
<img alt class="marginLeft" src="../../../assets/images/login-alipay.png" />
|
||||
<img alt class="marginLeft" src="../../../assets/images/login-sina.png" />
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { loginApi } from '@/api/login';
|
||||
import { PRIVILEGE_TYPE } from '@/constants/login';
|
||||
export default {
|
||||
name: 'LoginForm',
|
||||
props: {
|
||||
// 登录名规则
|
||||
loginNameRules: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [{ required: true, message: '账号不能为空', trigger: 'blur' }];
|
||||
}
|
||||
},
|
||||
// 密码规则
|
||||
loginPwdRules: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [{ required: true, message: '密码不能为空', trigger: 'blur' }];
|
||||
}
|
||||
},
|
||||
// 验证码规则
|
||||
codedRules: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [{ required: true, message: '验证码不能为空', trigger: 'blur' }];
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 防止重复提交 按钮加载状态
|
||||
btnLoading: false,
|
||||
formData: {
|
||||
code: '',
|
||||
codeUuid: '',
|
||||
loginName: 'sa',
|
||||
loginPwd: '123456'
|
||||
},
|
||||
codeUrl: ''
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
rules() {
|
||||
return {
|
||||
loginName: this.loginNameRules,
|
||||
loginPwd: this.loginPwdRules,
|
||||
code: this.codedRules
|
||||
};
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.verificationCode();
|
||||
},
|
||||
methods: {
|
||||
// 获取验证码
|
||||
async verificationCode() {
|
||||
let result = await loginApi.getVerificationCode();
|
||||
let datas = result.data;
|
||||
this.formData.codeUuid = datas.uuid;
|
||||
this.codeUrl = datas.code;
|
||||
},
|
||||
// 登录
|
||||
login() {
|
||||
this.$refs.loginForm.validate(valid => {
|
||||
if (valid) {
|
||||
this.loginSuccess();
|
||||
}
|
||||
});
|
||||
},
|
||||
// 登录 - 异步
|
||||
async loginSuccess() {
|
||||
try {
|
||||
this.btnLoading = true;
|
||||
let loginResult = await loginApi.login(this.formData);
|
||||
let loginInfo = loginResult.data;
|
||||
localStorage.clear();
|
||||
this.$store.commit('setToken', loginInfo.xaccessToken);
|
||||
// 保存用户登录
|
||||
this.$store.commit('setUserLoginInfo', {
|
||||
id: loginInfo.id,
|
||||
loginName: loginInfo.loginName,
|
||||
nickName: loginInfo.nickName,
|
||||
actualName: loginInfo.actualName,
|
||||
phone: loginInfo.phone,
|
||||
isSuperMan: loginInfo.isSuperMan
|
||||
});
|
||||
//设置权限
|
||||
this.$store.commit('setUserPrivilege', loginInfo.privilegeList);
|
||||
this.btnLoading = false;
|
||||
// 跳转到首页
|
||||
this.$router.push({
|
||||
name: this.$config.homeName
|
||||
});
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
this.btnLoading = false;
|
||||
this.verificationCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
128
smart-admin-web/src/views/login/login.less
Normal file
128
smart-admin-web/src/views/login/login.less
Normal file
@@ -0,0 +1,128 @@
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.login {
|
||||
font-family: Arial, "PingFang SC", "Microsoft YaHei";
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: url(../../assets/images/login-bg.jpg) no-repeat fixed;
|
||||
background-size: cover;
|
||||
|
||||
.content {
|
||||
width: 424px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -56%)
|
||||
}
|
||||
.ivu-card {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 10px;
|
||||
box-shadow: 5px 5px 15px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
.form-con {
|
||||
margin: 32px 0;
|
||||
width: 424px;
|
||||
background: #fff;
|
||||
padding: 32px 32px;
|
||||
border-radius: 0 8px 8px 0;
|
||||
.ivu-input {
|
||||
border: 1px solid #E8E8EE;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
color: #525252;
|
||||
padding: 0 20px;
|
||||
&:focus {
|
||||
border: 1px solid #0097F6;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
.ivu-form-item-error-tip {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
padding: 0;
|
||||
color: #f66;
|
||||
top:90%;
|
||||
}
|
||||
.ivu-form-item {
|
||||
margin-bottom: 22px;
|
||||
}
|
||||
.remember {
|
||||
margin: -10px 0 10px;
|
||||
}
|
||||
.ivu-input,
|
||||
.ivu-btn {
|
||||
height: 48px;
|
||||
}
|
||||
.ivu-btn {
|
||||
font-size: 16px;
|
||||
}
|
||||
.ivu-input-group-prepend {
|
||||
padding: 4px 15px;
|
||||
}
|
||||
.code-input {
|
||||
width: 172px;
|
||||
}
|
||||
.codeUrl {
|
||||
height: 80%;
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
right: 24px;
|
||||
border-radius: 0 4px 4px 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.login-tip {
|
||||
font-size: 10px;
|
||||
text-align: center;
|
||||
color: #c3c3c3;
|
||||
}
|
||||
.footerDesc {
|
||||
font-family: "MicrosoftYaHei";
|
||||
color: #A6A6A8;
|
||||
font-size: 14px;
|
||||
}
|
||||
.otherWay {
|
||||
font-size: 14px;
|
||||
font-family: "Microsoft YaHei";
|
||||
.inline {
|
||||
display: inline-block;
|
||||
}
|
||||
.align {
|
||||
vertical-align: middle;
|
||||
}
|
||||
.marginLeft {
|
||||
margin-left: 20px;
|
||||
float:right;
|
||||
}
|
||||
}
|
||||
.remember {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
.draw {
|
||||
position: fixed;
|
||||
width: 1px;
|
||||
z-index: 99999;
|
||||
line-height: 1px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@keyframes floatOne {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: translate3D(0, -20px, 0) scale(5) rotate(45deg);
|
||||
}
|
||||
}
|
||||
52
smart-admin-web/src/views/login/login.vue
Normal file
52
smart-admin-web/src/views/login/login.vue
Normal file
@@ -0,0 +1,52 @@
|
||||
<style lang="less">
|
||||
@import './login.less';
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div class="login">
|
||||
<div class="content">
|
||||
<header class="logo center">
|
||||
<img alt
|
||||
src="../../assets/images/login-logo.png" />
|
||||
</header>
|
||||
<div class="form-con">
|
||||
<login-form @on-success-valid="handleSubmit"></login-form>
|
||||
</div>
|
||||
<footer class="center footerDesc">SmartAdmin 由1024创新实验室强力驱动</footer>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import LoginForm from './components/login-form';
|
||||
import { mapActions } from 'vuex';
|
||||
import $ from 'jquery';
|
||||
import { lonWave, canvasParticle } from './canvas';
|
||||
export default {
|
||||
name: 'login',
|
||||
props: {},
|
||||
components: {
|
||||
LoginForm
|
||||
},
|
||||
data () {
|
||||
return {};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
filters: {},
|
||||
created () {},
|
||||
mounted () {
|
||||
this.$Spin.hide();
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['handleLogin']),
|
||||
// 提交
|
||||
handleSubmit (params) {
|
||||
this.handleLogin(params).then(res => {
|
||||
this.$router.push({
|
||||
name: this.$config.homeName
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
152
smart-admin-web/src/views/monitor/online-user.vue
Normal file
152
smart-admin-web/src/views/monitor/online-user.vue
Normal file
@@ -0,0 +1,152 @@
|
||||
<template>
|
||||
<div>
|
||||
<Card class="warp-card" dis-hover>
|
||||
<Form class="tools" inline v-privilege="'online-user-search'">
|
||||
<FormItem>
|
||||
<Input placeholder="请输入用户姓名" v-model="searchData.actualName">
|
||||
<Button @click="getOnlineUserList" icon="ios-search" slot="append"></Button>
|
||||
</Input>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button @click="refresh" type="primary">重置</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<p class="online-num">
|
||||
当前在线人数:
|
||||
<span>
|
||||
<count-to :end="pageTotal" />
|
||||
</span>人
|
||||
</p>
|
||||
<Table :columns="columns" :data="data" :loading="loading"></Table>
|
||||
<Page
|
||||
:current="pageNum"
|
||||
:page-size="pageSize"
|
||||
:page-size-opts="[10, 20, 30, 50, 100]"
|
||||
:total="pageTotal"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
show-elevator
|
||||
show-sizer
|
||||
show-total
|
||||
style="margin:24px 0;text-align:right;"
|
||||
></Page>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { onlineUserApi } from '@/api/online-user';
|
||||
import CountTo from '_c/count-to';
|
||||
export default {
|
||||
name: 'OnlineUser',
|
||||
props: {},
|
||||
components: {
|
||||
CountTo
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
searchData: {
|
||||
actualName: ''
|
||||
},
|
||||
modalType: 'add',
|
||||
editModal: false,
|
||||
addModal: false,
|
||||
loading: true,
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
pageTotal: 0,
|
||||
formData: {
|
||||
title: '',
|
||||
content: ''
|
||||
},
|
||||
// table表头
|
||||
columns: [
|
||||
{
|
||||
title: 'ID',
|
||||
key: 'id',
|
||||
width: 60,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '姓名',
|
||||
key: 'actualName'
|
||||
},
|
||||
{
|
||||
title: '登录账户',
|
||||
key: 'loginName'
|
||||
},
|
||||
{
|
||||
title: '手机号',
|
||||
key: 'phone'
|
||||
},
|
||||
|
||||
{
|
||||
title: '部门',
|
||||
key: 'departmentName'
|
||||
}
|
||||
],
|
||||
// table数据
|
||||
data: []
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
filters: {},
|
||||
created() {},
|
||||
mounted() {
|
||||
this.getOnlineUserList();
|
||||
},
|
||||
methods: {
|
||||
// 获取在线用户集合
|
||||
async getOnlineUserList() {
|
||||
this.loading = true;
|
||||
try {
|
||||
let result = await onlineUserApi.getOnlineUserList({
|
||||
...this.searchData,
|
||||
pageNum: this.pageNum,
|
||||
pageSize: this.pageSize
|
||||
});
|
||||
this.loading = false;
|
||||
this.data = result.data.list;
|
||||
this.pageTotal = result.data.total;
|
||||
this.pageNum = result.data.pageNum;
|
||||
this.pageSize = result.data.pageSize;
|
||||
} catch (e) {
|
||||
this.loading = true;
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
}
|
||||
},
|
||||
// 分页
|
||||
changePage(pageNum) {
|
||||
this.pageNum = pageNum;
|
||||
this.getOnlineUserList();
|
||||
},
|
||||
changePageSize(pageSize) {
|
||||
this.pageNum = 1;
|
||||
this.pageSize = pageSize;
|
||||
this.getOnlineUserList();
|
||||
},
|
||||
refresh() {
|
||||
this.pageNum = 1;
|
||||
this.searchData.actualName = '';
|
||||
this.getOnlineUserList();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.online-num {
|
||||
display: flex;
|
||||
margin: 10px 0;
|
||||
line-height: 0;
|
||||
font-size: 15px;
|
||||
padding: 10px 0;
|
||||
span {
|
||||
font-size: 18px;
|
||||
color: #2d8cf0;
|
||||
padding: 0 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
33
smart-admin-web/src/views/monitor/sql.vue
Normal file
33
smart-admin-web/src/views/monitor/sql.vue
Normal file
@@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<div>
|
||||
<iframe :src="url" frameborder="0" height="800" scrolling="yes" width="100%"></iframe>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import config from '@/config';
|
||||
const baseUrl = config.baseUrl.apiUrl;
|
||||
export default {
|
||||
name: 'Sql',
|
||||
components: {},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
url: baseUrl + '/druidMonitor'
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
filters: {},
|
||||
created() {},
|
||||
mounted() {},
|
||||
beforeCreate() {},
|
||||
beforeMount() {},
|
||||
beforeUpdate() {},
|
||||
updated() {},
|
||||
beforeDestroy() {},
|
||||
destroyed() {},
|
||||
activated() {},
|
||||
methods: {}
|
||||
};
|
||||
</script>
|
||||
397
smart-admin-web/src/views/notice/notice-list.vue
Normal file
397
smart-admin-web/src/views/notice/notice-list.vue
Normal file
@@ -0,0 +1,397 @@
|
||||
<template>
|
||||
<div>
|
||||
<Card class="warp-card" dis-hover>
|
||||
<Form class="tools" inline>
|
||||
<FormItem v-privilege="'notice-query'">
|
||||
<Input placeholder="请输入消息标题" v-model="searchData.title"></Input>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<ButtonGroup>
|
||||
<Button
|
||||
@click="getNoticeList"
|
||||
icon="ios-search"
|
||||
type="primary"
|
||||
v-privilege="'notice-query'"
|
||||
>查询</Button>
|
||||
<Button
|
||||
@click="refresh"
|
||||
icon="md-refresh"
|
||||
type="default"
|
||||
v-privilege="'notice-query'"
|
||||
>重置</Button>
|
||||
</ButtonGroup>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button
|
||||
@click="openModal('add')"
|
||||
icon="md-add"
|
||||
type="primary"
|
||||
v-privilege="'notice-add'"
|
||||
>添加消息</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<Table :columns="columns" :data="data" :loading="loading" border></Table>
|
||||
<Page
|
||||
:current="pageNum"
|
||||
:page-size="pageSize"
|
||||
:page-size-opts="[10, 20, 30, 50, 100]"
|
||||
:total="pageTotal"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
show-elevator
|
||||
show-sizer
|
||||
show-total
|
||||
style="margin:24px 0;text-align:right;"
|
||||
></Page>
|
||||
</Card>
|
||||
<!-- 添加修改消息 -->
|
||||
<Modal
|
||||
:loading="saveLoading"
|
||||
:title="modalType=='add'?'添加':'修改'"
|
||||
@on-cancel="cancelSave"
|
||||
@on-ok="addOrUpdateNotice"
|
||||
v-model="editModal"
|
||||
>
|
||||
<Form :label-width="80" :model="formData" :rules="formValidate" ref="formRef">
|
||||
<FormItem label="标题" prop="title">
|
||||
<Input placeholder="请输入消息标题" v-model="formData.title"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="内容" prop="content">
|
||||
<Input
|
||||
:autosize="{minRows: 2,maxRows: 5}"
|
||||
placeholder="请输入消息内容"
|
||||
type="textarea"
|
||||
v-model="formData.content"
|
||||
></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<!-- 添加修改消息 -->
|
||||
<!-- 消息详情 -->
|
||||
</Modal>
|
||||
<Modal
|
||||
:loading="saveLoading"
|
||||
:title="formData.title"
|
||||
class="detail-modal"
|
||||
v-model="detailModal"
|
||||
>
|
||||
<div class="detail">{{formData.content}}</div>
|
||||
<p class="time">{{formData.updateTime}}</p>
|
||||
<div slot="footer">
|
||||
<Button @click="cancelSave" size="large" type="primary">知道了</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
<!-- 消息详情 -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { noticeApi } from '@/api/notice';
|
||||
import { NOTICE_STATUS } from '@/constants/notice';
|
||||
export default {
|
||||
name: 'NoticeList',
|
||||
components: {},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
detailModal: false,
|
||||
searchData: {
|
||||
title: ''
|
||||
},
|
||||
modalType: 'add',
|
||||
editModal: false,
|
||||
addModal: false,
|
||||
loading: true,
|
||||
saveLoading: true,
|
||||
updateLoading: true,
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
pageTotal: 0,
|
||||
updateItem: {},
|
||||
saveItem: {},
|
||||
formData: {
|
||||
title: '',
|
||||
content: ''
|
||||
},
|
||||
// table表头
|
||||
columns: [
|
||||
{
|
||||
title: 'ID',
|
||||
width: 60,
|
||||
key: 'id'
|
||||
},
|
||||
{
|
||||
title: '消息标题',
|
||||
key: 'title'
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'createTime'
|
||||
},
|
||||
{
|
||||
title: '消息创建人',
|
||||
key: 'createUserName'
|
||||
},
|
||||
{
|
||||
title: '是否发送',
|
||||
key: 'sendStatus',
|
||||
render: (h, params) => {
|
||||
return h(
|
||||
'span',
|
||||
this.$enum.getDescByValue('NOTICE_STATUS', params.row.sendStatus)
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
className: 'action-hide',
|
||||
render: (h, params) => {
|
||||
let btns = [
|
||||
{
|
||||
title: '详情',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'notice-detail'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.openModal('detail', params.row);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '删除',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'notice-delete'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.$Modal.confirm({
|
||||
title: '删除',
|
||||
content: '确认删除该条消息么?',
|
||||
onOk: () => {
|
||||
this.deleteNotice(params.row.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
];
|
||||
let editBtn = {
|
||||
title: '编辑',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'notice-edit'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.openModal('edit', params.row);
|
||||
}
|
||||
};
|
||||
let sendBtn = {
|
||||
title: '发送',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'notice-send'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.$Modal.confirm({
|
||||
title: '确认',
|
||||
content: '确认发送条消息么?',
|
||||
onOk: () => {
|
||||
this.sendNotice(params.row.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
if (params.row.sendStatus != NOTICE_STATUS['YES'].value) {
|
||||
btns.push(editBtn);
|
||||
}
|
||||
if (params.row.sendStatus != NOTICE_STATUS['YES'].value) {
|
||||
btns.push(sendBtn);
|
||||
}
|
||||
return this.$tableAction(h, btns);
|
||||
}
|
||||
}
|
||||
],
|
||||
// table数据
|
||||
data: [],
|
||||
formValidate: {
|
||||
title: [{ required: true, message: '请输入消息标题', trigger: 'blur' }],
|
||||
content: [
|
||||
{ required: true, message: '请输入消息内容', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
filters: {},
|
||||
created() {},
|
||||
mounted() {
|
||||
this.getNoticeList();
|
||||
},
|
||||
beforeCreate() {},
|
||||
beforeMount() {},
|
||||
beforeUpdate() {},
|
||||
updated() {},
|
||||
beforeDestroy() {},
|
||||
destroyed() {},
|
||||
activated() {},
|
||||
methods: {
|
||||
// 查询消息列表
|
||||
async getNoticeList() {
|
||||
try {
|
||||
this.loading = true;
|
||||
let result = await noticeApi.getNoticeList({
|
||||
...this.searchData,
|
||||
pageNum: this.pageNum,
|
||||
pageSize: this.pageSize
|
||||
});
|
||||
this.loading = false;
|
||||
this.data = result.data.list;
|
||||
this.pageTotal = result.data.total;
|
||||
this.pageNum = result.data.pageNum;
|
||||
this.pageSize = result.data.pageSize;
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
}
|
||||
},
|
||||
// 获取通知详情
|
||||
async getNoticeDetail(id) {
|
||||
try {
|
||||
this.loading = true;
|
||||
let result = await noticeApi.getNoticeDetail(id);
|
||||
this.loading = false;
|
||||
this.formData = result.data;
|
||||
} catch (e) {
|
||||
this.loading = true;
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
}
|
||||
},
|
||||
// 添加消息
|
||||
openModal(type, data) {
|
||||
this.modalType = type;
|
||||
switch (type) {
|
||||
case 'add':
|
||||
this.formData = {};
|
||||
this.editModal = true;
|
||||
break;
|
||||
case 'edit':
|
||||
this.getNoticeDetail(data.id);
|
||||
this.editModal = true;
|
||||
break;
|
||||
case 'detail':
|
||||
this.getNoticeDetail(data.id);
|
||||
this.detailModal = true;
|
||||
break;
|
||||
}
|
||||
},
|
||||
// 分页
|
||||
changePage(pageNum) {
|
||||
this.pageNum = pageNum;
|
||||
this.getNoticeList();
|
||||
},
|
||||
// 更改分页查询条数
|
||||
changePageSize(pageSize) {
|
||||
this.pageNum = 1;
|
||||
this.pageSize = pageSize;
|
||||
this.getNoticeList();
|
||||
},
|
||||
// 删除通知
|
||||
async deleteNotice(id) {
|
||||
this.$Spin.show();
|
||||
let result = await noticeApi.deleteNotice(id);
|
||||
this.$Spin.hide();
|
||||
this.$Message.success('删除消息成功!');
|
||||
this.getNoticeList();
|
||||
},
|
||||
// 发送消息
|
||||
async sendNotice(id) {
|
||||
this.$Spin.show();
|
||||
let result = await noticeApi.sendNotice(id);
|
||||
this.$Message.success('发送消息成功!');
|
||||
this.$Spin.hide();
|
||||
this.getNoticeList();
|
||||
},
|
||||
// 保存任务
|
||||
addOrUpdateNotice() {
|
||||
try {
|
||||
this.$refs['formRef'].validate(valid => {
|
||||
if (valid) {
|
||||
if (this.modalType == 'add') {
|
||||
this.addNotice();
|
||||
} else {
|
||||
this.editNotice();
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
}
|
||||
},
|
||||
// 修改消息
|
||||
async editNotice() {
|
||||
try {
|
||||
this.loading = true;
|
||||
let result = await noticeApi.updateNotice(this.formData);
|
||||
this.$Message.success('修改成功');
|
||||
this.editModal = false;
|
||||
this.getNoticeList();
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
// 保存消息
|
||||
async addNotice() {
|
||||
try {
|
||||
this.loading = true;
|
||||
let result = await noticeApi.addNotice(this.formData);
|
||||
this.$Message.success('添加成功');
|
||||
this.editModal = false;
|
||||
this.getNoticeList();
|
||||
this.loading = false;
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
// 取消添加/修改
|
||||
cancelSave() {
|
||||
this.editModal = false;
|
||||
this.detailModal = false;
|
||||
this.$refs['formRef'].resetFields();
|
||||
},
|
||||
// 重置
|
||||
refresh() {
|
||||
this.pageNum = 1;
|
||||
this.searchData.title = '';
|
||||
this.getNoticeList();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.detail-modal {
|
||||
.detail {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.time {
|
||||
text-align: right;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
221
smart-admin-web/src/views/notice/person-notice.vue
Normal file
221
smart-admin-web/src/views/notice/person-notice.vue
Normal file
@@ -0,0 +1,221 @@
|
||||
<template>
|
||||
<div>
|
||||
<Card class="warp-card" dis-hover>
|
||||
<Form class="tools" inline>
|
||||
<FormItem v-privilege="'person-notice-query'">
|
||||
<Input placeholder="请输入消息标题" v-model="searchData.title">
|
||||
<Button @click="getPersonNoticeList" icon="ios-search" slot="append"></Button>
|
||||
</Input>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button
|
||||
@click="refresh"
|
||||
icon="md-refresh"
|
||||
type="primary"
|
||||
v-privilege="'person-notice-query'"
|
||||
>重置</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<Table :columns="columns" :data="data" :loading="loading" border></Table>
|
||||
<Page
|
||||
:current="pageNum"
|
||||
:page-size="pageSize"
|
||||
:page-size-opts="[10, 20, 30, 50, 100]"
|
||||
:total="pageTotal"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
show-elevator
|
||||
show-sizer
|
||||
show-total
|
||||
style="margin:24px 0;text-align:right;"
|
||||
></Page>
|
||||
</Card>
|
||||
<Modal :loading="saveLoading" :title="formData.title" class="detail-modal" v-model="editModal">
|
||||
<div class="detail">{{formData.content}}</div>
|
||||
<p class="time">{{formData.updateTime}}</p>
|
||||
<div slot="footer">
|
||||
<Button @click="cancelSave" size="large" type="primary">知道了</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { noticeApi } from '@/api/notice';
|
||||
export default {
|
||||
name: 'PersonNotice',
|
||||
components: {},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
searchData: {
|
||||
title: ''
|
||||
},
|
||||
modalType: 'add',
|
||||
editModal: false,
|
||||
addModal: false,
|
||||
loading: true,
|
||||
saveLoading: true,
|
||||
updateLoading: true,
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
pageTotal: 0,
|
||||
updateItem: {},
|
||||
saveItem: {},
|
||||
formData: {
|
||||
title: '',
|
||||
content: ''
|
||||
},
|
||||
// table表头
|
||||
columns: [
|
||||
{
|
||||
title: 'ID',
|
||||
width: 60,
|
||||
key: 'id'
|
||||
},
|
||||
{
|
||||
title: '消息标题',
|
||||
key: 'title'
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'receiveTime'
|
||||
},
|
||||
{
|
||||
title: '消息创建人',
|
||||
key: 'createUserName'
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
key: 'createUser',
|
||||
render: (h, params) => {
|
||||
return h('span', params.row.readStatus ? '已读' : '未读');
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
className: 'action-hide',
|
||||
render: (h, params) => {
|
||||
return this.$tableAction(h, [
|
||||
{
|
||||
title: '查看',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'person-notice-detail'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.getNoticeDetail(params.row.id);
|
||||
}
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
],
|
||||
// table数据
|
||||
data: [],
|
||||
formValidate: {
|
||||
title: [{ required: true, message: '请输入消息标题', trigger: 'blur' }],
|
||||
content: [
|
||||
{ required: true, message: '请输入消息内容', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
filters: {},
|
||||
created() {},
|
||||
mounted() {
|
||||
this.getPersonNoticeList();
|
||||
},
|
||||
beforeCreate() {},
|
||||
beforeMount() {},
|
||||
beforeUpdate() {},
|
||||
updated() {},
|
||||
beforeDestroy() {},
|
||||
destroyed() {},
|
||||
activated() {},
|
||||
methods: {
|
||||
// 查询个人消息列表
|
||||
async getPersonNoticeList() {
|
||||
try {
|
||||
this.loading = true;
|
||||
let result = await noticeApi.getPersonNoticeList({
|
||||
...this.searchData,
|
||||
pageNum: this.pageNum,
|
||||
pageSize: this.pageSize
|
||||
});
|
||||
this.loading = false;
|
||||
this.data = result.data.list;
|
||||
this.pageTotal = result.data.total;
|
||||
this.pageNum = result.data.pageNum;
|
||||
this.pageSize = result.data.pageSize;
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
this.loading = false;
|
||||
console.error(e);
|
||||
}
|
||||
},
|
||||
// 获取通知详情
|
||||
async getNoticeDetail(id) {
|
||||
try {
|
||||
this.loading = true;
|
||||
let result = await noticeApi.getNoticeDetail(id);
|
||||
this.loading = false;
|
||||
this.formData = result.data;
|
||||
this.openModal(result.data);
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
this.loading = false;
|
||||
console.error(e);
|
||||
}
|
||||
},
|
||||
// 标记已读
|
||||
async openModal(data) {
|
||||
this.editModal = true;
|
||||
this.$Spin.show();
|
||||
let result = await noticeApi.addNoticeRecord(data.id);
|
||||
this.$Spin.hide();
|
||||
},
|
||||
// 分页
|
||||
changePage(pageNum) {
|
||||
this.pageNum = pageNum;
|
||||
this.getPersonNoticeList();
|
||||
},
|
||||
// 更改分页查询条数
|
||||
changePageSize(pageSize) {
|
||||
this.pageNum = 1;
|
||||
this.pageSize = pageSize;
|
||||
this.getPersonNoticeList();
|
||||
},
|
||||
// 重置
|
||||
refresh() {
|
||||
this.pageNum = 1;
|
||||
this.searchData.title = '';
|
||||
this.getPersonNoticeList();
|
||||
},
|
||||
// 关闭详情
|
||||
cancelSave() {
|
||||
this.editModal = false;
|
||||
this.getPersonNoticeList();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.detail-modal {
|
||||
.detail {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.time {
|
||||
text-align: right;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,273 @@
|
||||
<template>
|
||||
<Card class="warp-card" dis-hover>
|
||||
<Form class="tools" inline>
|
||||
<FormItem>
|
||||
<Button
|
||||
@click="getSmartReloadList"
|
||||
icon="md-refresh"
|
||||
type="primary"
|
||||
v-privilege="'smart-reload-search'"
|
||||
>刷新</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<Alert>
|
||||
<h3>SmartReload介绍:</h3>
|
||||
<pre>
|
||||
简介:SmartReload是一个可以在不重启进程的情况下动态重新加载配置或者执行某些预先设置的代码。
|
||||
|
||||
原理:
|
||||
- Java后端会在项目启动的时候开启一个Daemon线程,这个Daemon线程会每隔几秒轮询t_smart_item表的状态。
|
||||
- 如果【状态标识】与【上次状态标识】比较发生变化,会将参数传入SmartReload实现类,进行自定义操作。
|
||||
用途:
|
||||
· 用于刷新内存中的缓存
|
||||
· 用于执行某些后门代码
|
||||
· 用于进行Java热加载(前提是类结构不发生变化)
|
||||
· 其他不能重启服务的应用
|
||||
</pre>
|
||||
</Alert>
|
||||
<Table :columns="columns" :data="tableData" :loading="tableLoading" border></Table>
|
||||
<Modal
|
||||
:closable="false"
|
||||
:mask-closable="false"
|
||||
@on-cancel="editModal=false"
|
||||
@on-ok="updateSmartReloadData"
|
||||
title="编辑"
|
||||
v-model="editModal"
|
||||
>
|
||||
<Form :label-width="80" :model="formData">
|
||||
<FormItem label="标签">
|
||||
<Input disabled="disabled" v-model="formData.tag" />
|
||||
</FormItem>
|
||||
<FormItem label="状态标识">
|
||||
<Input required v-model="formData.identification" />
|
||||
</FormItem>
|
||||
<FormItem label="Reload参数(非必填)">
|
||||
<Input
|
||||
:autosize="{minRows: 2,maxRows: 5}"
|
||||
placeholder="传入SmartReload的参数"
|
||||
type="textarea"
|
||||
v-model="formData.args"
|
||||
/>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
<Modal
|
||||
:closable="false"
|
||||
:mask-closable="false"
|
||||
title="执行结果"
|
||||
v-model="showResultModal"
|
||||
width="1000px"
|
||||
>
|
||||
<Table :columns="resultColumns" :data="resultData" height="500"></Table>
|
||||
<div slot="footer">
|
||||
<Button @click="showResultModal=false" type="primary">关闭</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</Card>
|
||||
</template>
|
||||
<script>
|
||||
import { smartReloadApi } from '@/api/smart-reload';
|
||||
export default {
|
||||
name: 'SmartReloadList',
|
||||
components: {},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
//表格loading
|
||||
tableLoading: false,
|
||||
//reload结果弹出框
|
||||
showResultModal: false,
|
||||
// 修改弹窗
|
||||
editModal: false,
|
||||
formData: {
|
||||
tag: '',
|
||||
identification: 0,
|
||||
args: ''
|
||||
},
|
||||
tableData: [],
|
||||
columns: [
|
||||
{
|
||||
title: '标签',
|
||||
key: 'tag'
|
||||
},
|
||||
{
|
||||
title: '状态标识',
|
||||
key: 'identification'
|
||||
},
|
||||
{
|
||||
title: '更新时间',
|
||||
key: 'updateTime'
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'createTime'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
width: 200,
|
||||
align: 'center',
|
||||
render: (h, param) => {
|
||||
return this.$tableAction(h, [
|
||||
{
|
||||
title: '执行Reload',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'smart-reload-update'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.editModal = true;
|
||||
this.formData.tag = param.row.tag;
|
||||
this.formData.identification = param.row.identification;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '查看结果',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'smart-reload-result'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.getSmartReloadResult(param.row.tag);
|
||||
}
|
||||
}
|
||||
]);
|
||||
s;
|
||||
}
|
||||
}
|
||||
],
|
||||
resultData: [],
|
||||
resultColumns: [
|
||||
{
|
||||
type: 'expand',
|
||||
width: 50,
|
||||
render: (h, params) => {
|
||||
return h('pre', {}, params.row.exception);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '标签',
|
||||
key: 'tag',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '状态标识',
|
||||
key: 'identification'
|
||||
},
|
||||
{
|
||||
title: '参数',
|
||||
key: 'args',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '结果',
|
||||
key: 'result',
|
||||
render: (h, params) => {
|
||||
if (params.row.result) {
|
||||
return h(
|
||||
'span',
|
||||
{
|
||||
style: {
|
||||
color: '#19be6b'
|
||||
}
|
||||
},
|
||||
'成功'
|
||||
);
|
||||
} else {
|
||||
return h(
|
||||
'span',
|
||||
{
|
||||
style: {
|
||||
color: '#ed4014'
|
||||
}
|
||||
},
|
||||
'失败'
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '异常信息',
|
||||
key: 'exception',
|
||||
width: 200,
|
||||
render: (h, params) => {
|
||||
if (params.row.result) {
|
||||
return h(
|
||||
'span',
|
||||
{
|
||||
style: {
|
||||
color: '#19be6b'
|
||||
}
|
||||
},
|
||||
'无异常信息'
|
||||
);
|
||||
} else {
|
||||
return h(
|
||||
'span',
|
||||
{
|
||||
style: {
|
||||
color: '#ed4014'
|
||||
}
|
||||
},
|
||||
'有异常信息,请点开Expand'
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'createTime',
|
||||
width: 180
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
filters: {},
|
||||
created() {},
|
||||
mounted() {
|
||||
this.getSmartReloadList();
|
||||
},
|
||||
methods: {
|
||||
// 查询
|
||||
async getSmartReloadList() {
|
||||
try {
|
||||
this.tableLoading = true;
|
||||
let result = await smartReloadApi.getSmartReloadList();
|
||||
this.tableData = result.data;
|
||||
this.tableLoading = false;
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
this.tableLoading = false;
|
||||
}
|
||||
},
|
||||
// 修改
|
||||
async updateSmartReloadData() {
|
||||
if (this.formData.identification) {
|
||||
this.$Spin.show();
|
||||
let result = await smartReloadApi.updateSmartReloadData(this.formData);
|
||||
this.$Spin.hide();
|
||||
this.$Message.success('更新成功');
|
||||
this.formData = {};
|
||||
this.getSmartReloadList();
|
||||
} else {
|
||||
this.$Message.error('状态标示不能为空');
|
||||
this.show = true;
|
||||
}
|
||||
},
|
||||
// 获取执行结果
|
||||
async getSmartReloadResult(tag) {
|
||||
this.$Spin.show();
|
||||
this.showResultModal = true;
|
||||
let result = await smartReloadApi.getSmartReloadResult(tag);
|
||||
this.$Spin.hide();
|
||||
this.resultData = result.data;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,397 @@
|
||||
<template>
|
||||
<div>
|
||||
<Card class="warp-card" dis-hover>
|
||||
<Form class="tools" inline>
|
||||
<FormItem>
|
||||
<Input placeholder="请输入" v-model="searchValue" v-privilege="'system-params-search'">
|
||||
<Select slot="prepend" style="width: 120px" v-model="searchType">
|
||||
<Option value="BY_KEY">按key</Option>
|
||||
<Option value="BY_GROUP">按参数类别</Option>
|
||||
</Select>
|
||||
</Input>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<ButtonGroup>
|
||||
<Button
|
||||
@click="searchSystemConfigList"
|
||||
icon="ios-search"
|
||||
type="primary"
|
||||
v-privilege="'system-params-search'"
|
||||
>查询</Button>
|
||||
<Button
|
||||
@click="refresh"
|
||||
icon="md-refresh"
|
||||
type="default"
|
||||
v-privilege="'system-params-search'"
|
||||
>重置</Button>
|
||||
</ButtonGroup>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button
|
||||
@click="addModal=true"
|
||||
icon="md-add"
|
||||
type="primary"
|
||||
v-privilege="'system-params-add'"
|
||||
>添加</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<Table
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:loading="loading"
|
||||
:pageNumber="pageNum"
|
||||
:pageShow="pageShow"
|
||||
border
|
||||
></Table>
|
||||
<Page
|
||||
:current="pageNum"
|
||||
:page-size="pageSize"
|
||||
:total="pageTotal"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
show-elevator
|
||||
show-total
|
||||
style="margin:24px 0;text-align:right;"
|
||||
/>
|
||||
</Card>
|
||||
<Modal @on-cancel="cancelUpdate" @on-ok="handleUpdate" title="编辑" v-model="editModal">
|
||||
<Form :label-width="80" :model="updateItem" :rules="updateValidate" ref="updateRef">
|
||||
<FormItem label="Key">
|
||||
<Input disabled="disabled" v-model="updateItem.configKey"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="标题">
|
||||
<Input disabled="disabled" type="textarea" v-model="updateItem.configName" />
|
||||
</FormItem>
|
||||
<FormItem label="参数类别" prop="configGroup">
|
||||
<Input disabled="disabled" placeholder="请输入数据类型(必填)" v-model="updateItem.configGroup" />
|
||||
</FormItem>
|
||||
<FormItem label="值" prop="configValue">
|
||||
<Input
|
||||
:autosize="{minRows: 5}"
|
||||
placeholder="请输入值(必填)"
|
||||
type="textarea"
|
||||
v-model="updateItem.configValue"
|
||||
></Input>
|
||||
</FormItem>
|
||||
|
||||
<FormItem label="备注" prop="remark">
|
||||
<Input
|
||||
:autosize="{minRows: 4}"
|
||||
placeholder="请输入备注"
|
||||
type="textarea"
|
||||
v-model="updateItem.remark "
|
||||
></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer">
|
||||
<Button @click="cancelUpdate" type="text">取消</Button>
|
||||
<Button @click="handleUpdate" type="primary">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
<Modal title="添加" v-model="addModal">
|
||||
<Form :label-width="80" :model="saveItem" :rules="saveValidate" ref="saveRef">
|
||||
<FormItem label="Key" prop="configKey">
|
||||
<Input placeholder="请输入key(必填)" v-model="saveItem.configKey" />
|
||||
</FormItem>
|
||||
<FormItem label="标题" prop="configName">
|
||||
<Input placeholder="请输入标题(必填)" v-model="saveItem.configName" />
|
||||
</FormItem>
|
||||
<FormItem label="参数类别" prop="configGroup">
|
||||
<Input placeholder="请输入数据类型(必填)" v-model="saveItem.configGroup" />
|
||||
</FormItem>
|
||||
<FormItem label="值" prop="configValue">
|
||||
<Input
|
||||
:autosize="{minRows: 5}"
|
||||
placeholder="请输入值(必填)"
|
||||
type="textarea"
|
||||
v-model="saveItem.configValue"
|
||||
></Input>
|
||||
</FormItem>
|
||||
<FormItem label="备注" prop="remark">
|
||||
<Input
|
||||
:autosize="{minRows: 4}"
|
||||
placeholder="请输入备注"
|
||||
type="textarea"
|
||||
v-model="saveItem.remark "
|
||||
></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer">
|
||||
<Button @click="cancelSave" type="text">取消</Button>
|
||||
<Button @click="handleSave" type="primary">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<Modal :closable="false" :mask-closable="false" title="值查看" v-model="valueModal">
|
||||
<json-viewer :expand-depth="10" :value="valueData" boxed copyable sort></json-viewer>
|
||||
<div slot="footer">
|
||||
<Button @click="cancelValueModal" type="primary">关闭</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { systemConfigApi } from '@/api/system-config';
|
||||
export default {
|
||||
name: 'SystemConfig',
|
||||
components: {},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
pageShow: true,
|
||||
searchValue: '',
|
||||
searchType: 'BY_KEY',
|
||||
editModal: false,
|
||||
addModal: false,
|
||||
valueModal: false,
|
||||
// table是否loading
|
||||
loading: true,
|
||||
saveLoading: true,
|
||||
updateLoading: true,
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
pageTotal: 0,
|
||||
updateItem: {
|
||||
id: 0,
|
||||
configKey: '',
|
||||
configName: '',
|
||||
configValue: '',
|
||||
remark: ''
|
||||
},
|
||||
saveItem: {
|
||||
configKey: '',
|
||||
configName: '',
|
||||
configValue: '',
|
||||
configGroup: '',
|
||||
remark: ''
|
||||
},
|
||||
valueData: '',
|
||||
// table表头
|
||||
columns: [
|
||||
{
|
||||
title: 'ID',
|
||||
key: 'id',
|
||||
width: 60
|
||||
},
|
||||
{
|
||||
title: 'Key',
|
||||
key: 'configKey'
|
||||
},
|
||||
{
|
||||
title: '标题',
|
||||
key: 'configName'
|
||||
},
|
||||
{
|
||||
title: '值',
|
||||
key: 'configValue',
|
||||
width: 200,
|
||||
ellipsis: true,
|
||||
tooltip: true
|
||||
},
|
||||
{
|
||||
title: '参数类别',
|
||||
key: 'configGroup'
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
key: 'remark'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
className: 'action-hide',
|
||||
render: (h, params) => {
|
||||
return this.$tableAction(h, [
|
||||
{
|
||||
title: '编辑',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'system-config-update'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.updateItem.id = params.row.id;
|
||||
this.updateItem.configGroup = params.row.configGroup;
|
||||
this.updateItem.configKey = params.row.configKey;
|
||||
this.updateItem.configName = params.row.configName;
|
||||
this.updateItem.configValue = params.row.configValue;
|
||||
this.updateItem.remark = params.row.remark;
|
||||
this.editModal = true;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '查看值',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'system-config-search'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
try {
|
||||
let valueData = JSON.parse(params.row.configValue);
|
||||
if (typeof valueData === 'object' && valueData) {
|
||||
this.valueData = valueData;
|
||||
} else {
|
||||
this.valueData = params.row.configValue;
|
||||
}
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
this.valueData = params.row.configValue;
|
||||
}
|
||||
this.valueModal = true;
|
||||
}
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
],
|
||||
// table数据
|
||||
data: [],
|
||||
// 验证规则
|
||||
updateValidate: {
|
||||
configValue: [{ required: true, message: '请输入值', trigger: 'blur' }]
|
||||
},
|
||||
saveValidate: {
|
||||
configKey: [{ required: true, message: '请输入Key', trigger: 'blur' }],
|
||||
configName: [
|
||||
{ required: true, message: '请输入标题', trigger: 'blur' }
|
||||
],
|
||||
configValue: [{ required: true, message: '请输入值', trigger: 'blur' }],
|
||||
configGroup: [
|
||||
{ required: true, message: '请输入参数类别', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
filters: {},
|
||||
created() {},
|
||||
mounted() {
|
||||
this.getSystemConfigList();
|
||||
},
|
||||
beforeCreate() {},
|
||||
beforeMount() {},
|
||||
beforeUpdate() {},
|
||||
updated() {},
|
||||
beforeDestroy() {},
|
||||
destroyed() {},
|
||||
activated() {},
|
||||
methods: {
|
||||
// 查询系统参数列表
|
||||
async getSystemConfigList() {
|
||||
this.loading = true;
|
||||
this.pageShow = true;
|
||||
let searchForm = {};
|
||||
if (this.searchType === 'BY_KEY') {
|
||||
searchForm['key'] = this.searchValue;
|
||||
} else {
|
||||
searchForm['configGroup'] = this.searchValue;
|
||||
}
|
||||
let result = await systemConfigApi.getSystemConfigList({
|
||||
...searchForm,
|
||||
pageNum: this.pageNum,
|
||||
pageSize: this.pageSize
|
||||
});
|
||||
this.loading = false;
|
||||
this.data = result.data.list;
|
||||
this.pageTotal = result.data.total;
|
||||
this.pageNum = result.data.pageNum;
|
||||
this.pageSize = result.data.pageSize;
|
||||
},
|
||||
// 分页
|
||||
changePage(pageNum) {
|
||||
this.pageNum = pageNum;
|
||||
this.getSystemConfigList();
|
||||
},
|
||||
// 更改分页查询条数
|
||||
changePageSize(pageSize) {
|
||||
this.pageNum = 1;
|
||||
this.pageSize = pageSize;
|
||||
this.getSystemConfigList();
|
||||
},
|
||||
// 修改
|
||||
handleUpdate() {
|
||||
this.$refs['updateRef'].validate(valid => {
|
||||
if (valid) {
|
||||
this.updateSystemConfig();
|
||||
}
|
||||
});
|
||||
},
|
||||
// 修改系统设置信息
|
||||
async updateSystemConfig() {
|
||||
this.$Spin.show();
|
||||
let result = await systemConfigApi.updateSystemConfig(this.updateItem);
|
||||
this.$Spin.hide();
|
||||
this.$Message.success('修改成功');
|
||||
this.getSystemConfigList();
|
||||
this.cancelUpdate();
|
||||
},
|
||||
// 搜索
|
||||
searchSystemConfigList() {
|
||||
this.pageNum = 1;
|
||||
this.getSystemConfigList();
|
||||
},
|
||||
// 保存系统设置信息
|
||||
handleSave() {
|
||||
try {
|
||||
this.$refs['saveRef'].validate(valid => {
|
||||
if (valid) {
|
||||
this.addSystemConfig();
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.log(e);
|
||||
}
|
||||
},
|
||||
// 新增
|
||||
async addSystemConfig() {
|
||||
try {
|
||||
this.saveLoading = true;
|
||||
let result = await systemConfigApi.addSystemConfig(this.saveItem);
|
||||
this.saveLoading = false;
|
||||
this.$Message.success('添加成功');
|
||||
this.getSystemConfigList();
|
||||
this.cancelSave();
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.log(e);
|
||||
this.saveLoading = false;
|
||||
}
|
||||
},
|
||||
// 取消
|
||||
cancelSave() {
|
||||
this.saveItem = {};
|
||||
// 清空form规则检查
|
||||
this.$refs['saveRef'].resetFields();
|
||||
this.addModal = false;
|
||||
},
|
||||
// 取消模态框
|
||||
cancelValueModal() {
|
||||
this.valueData = '';
|
||||
this.valueModal = false;
|
||||
},
|
||||
// 取消
|
||||
cancelUpdate() {
|
||||
this.updateItem = {};
|
||||
// 清空form规则检查
|
||||
this.$refs['updateRef'].resetFields();
|
||||
this.editModal = false;
|
||||
},
|
||||
// 刷新
|
||||
refresh() {
|
||||
this.pageNum = 1;
|
||||
this.searchType = 'BY_KEY';
|
||||
this.searchValue = '';
|
||||
this.getSystemConfigList();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<Modal
|
||||
:closable="false"
|
||||
:mask-closable="false"
|
||||
:title="privilege.functionName"
|
||||
:width="680"
|
||||
@on-ok="submitForm()"
|
||||
v-model="show"
|
||||
>
|
||||
<Form :label-width="100" :model="privilege" ref="privilegeFormRef">
|
||||
<Form-item label="菜单名称:" required>
|
||||
<Input disabled placeholder="请输入菜单名称" v-model="title"></Input>
|
||||
</Form-item>
|
||||
<Form-item label="功能点名称:" prop="functionName" required>
|
||||
<Input disabled placeholder="请输入功能点名称" v-model="privilege.functionName"></Input>
|
||||
</Form-item>
|
||||
<Form-item label="功能Key:" prop="functionKey" required>
|
||||
<Input disabled placeholder="请输入功能Key" v-model="privilege.functionKey"></Input>
|
||||
</Form-item>
|
||||
<Form-item label="Url:" required>
|
||||
<Select filterable multiple v-model="urlArray">
|
||||
<OptionGroup :key="i" :label="items.label" v-for="(items, i) in urlList">
|
||||
<Option :key="j" :label="item.url" :value="item.name" v-for="(item, j) in items.data">
|
||||
<span>{{item.url}}</span>
|
||||
<span style="float:right;color:#ccc">{{item.comment}}</span>
|
||||
</Option>
|
||||
</OptionGroup>
|
||||
</Select>
|
||||
</Form-item>
|
||||
</Form>
|
||||
<div slot="footer">
|
||||
<Button @click="submitForm" type="primary">保存</Button>
|
||||
<Button @click="cancel" type="default">取消</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { privilegeApi } from '@/api/privilege';
|
||||
export default {
|
||||
name: 'PrivilegeForm',
|
||||
components: {},
|
||||
// 类型禁用
|
||||
props: {
|
||||
typeDisabled: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
require: false
|
||||
},
|
||||
// 是否显示
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
require: true
|
||||
},
|
||||
// 标题
|
||||
title: {
|
||||
type: String,
|
||||
require: true
|
||||
},
|
||||
// 权限
|
||||
privilege: {
|
||||
type: Object,
|
||||
require: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
scope: 1, // 权限划分 1管理端权限 2web端权限 ,
|
||||
urlList: [],
|
||||
privilegeNameTitle: '菜单名称',
|
||||
urlArray: []
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {
|
||||
privilege(val) {
|
||||
if (val) {
|
||||
this.urlArray = val.url.split(',');
|
||||
}
|
||||
}
|
||||
},
|
||||
filters: {},
|
||||
created() {},
|
||||
mounted() {
|
||||
this.getAllUrl();
|
||||
},
|
||||
beforeCreate() {},
|
||||
beforeMount() {},
|
||||
beforeUpdate() {},
|
||||
updated() {},
|
||||
beforeDestroy() {},
|
||||
destroyed() {},
|
||||
activated() {},
|
||||
methods: {
|
||||
// 获取所有请求路径
|
||||
async getAllUrl() {
|
||||
this.$Spin.show();
|
||||
let result = await privilegeApi.getAllUrl(this.scope);
|
||||
this.$Spin.hide();
|
||||
let key = 1;
|
||||
let datas = result.data;
|
||||
let list = [];
|
||||
let keys = [];
|
||||
datas.map(item => {
|
||||
let type = item.name.split('.')[0];
|
||||
let index = keys.indexOf(type);
|
||||
if (index < 0) {
|
||||
keys.push(type);
|
||||
list.push({
|
||||
label: type,
|
||||
data: [item]
|
||||
});
|
||||
} else {
|
||||
list[index].data.push(item);
|
||||
}
|
||||
});
|
||||
this.urlList = list;
|
||||
},
|
||||
//保存当前弹窗
|
||||
cancel() {
|
||||
this.$emit('closeModal');
|
||||
},
|
||||
// 提交数据
|
||||
submitForm() {
|
||||
let params = Object.assign({}, this.privilege);
|
||||
if (this.urlArray.length === 0) {
|
||||
this.$Message.error('请选择Url!');
|
||||
return;
|
||||
}
|
||||
params.url = this.urlArray.join(',');
|
||||
this.addOrUpdate(params);
|
||||
},
|
||||
// 保存更新功能点
|
||||
async addOrUpdate(prams) {
|
||||
this.$Spin.show();
|
||||
let result = await privilegeApi.addOrUpdate(prams);
|
||||
this.$Message.success('修改成功');
|
||||
this.$Spin.hide();
|
||||
this.$emit('updateMenuSuccess', prams.menuKey);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,318 @@
|
||||
<template>
|
||||
<Row :gutter="10">
|
||||
<!--菜单管理-->
|
||||
<Col :lg="6" :md="8">
|
||||
<Card class="warp-card" dis-hover>
|
||||
<div class="card-title" slot="title">
|
||||
<Icon type="ios-switch"></Icon>菜单管理
|
||||
</div>
|
||||
<div slot="extra">
|
||||
<Button
|
||||
@click="addBatchSaveMenu"
|
||||
icon="md-add"
|
||||
size="small"
|
||||
type="primary"
|
||||
v-if="menusChange"
|
||||
>批量保存</Button>
|
||||
</div>
|
||||
<Alert show-icon type="warning" v-if="menusChange">有 {{this.menusChangeNum}} 个更新,请立即批量保存!</Alert>
|
||||
<Menu
|
||||
:active-name="activeName"
|
||||
@on-select="loadPrivilegeTableData"
|
||||
ref="defineSelect"
|
||||
width="100%"
|
||||
>
|
||||
<!--遍历得到模块-->
|
||||
<template v-for="(item, i) in menuTree">
|
||||
<Submenu :key="i" :name="item.menuKey">
|
||||
<template slot="title">
|
||||
<span>{{item.menuName}}</span>
|
||||
</template>
|
||||
<!--遍历得到子模块-->
|
||||
<template v-for="(children, j) in item.children">
|
||||
<Submenu :key="j" :name="children.menuKey" v-if="children.children.length > 0">
|
||||
<template slot="title">
|
||||
<span>{{children.menuName}}</span>
|
||||
</template>
|
||||
<!--遍历得到子模块页面-->
|
||||
<template v-for="(childrenPages, k) in children.children">
|
||||
<MenuItem :key="k" :name="childrenPages.menuKey">{{childrenPages.menuName}}</MenuItem>
|
||||
</template>
|
||||
</Submenu>
|
||||
<MenuItem :key="j" :name="children.menuKey" v-else>{{children.menuName}}</MenuItem>
|
||||
</template>
|
||||
</Submenu>
|
||||
</template>
|
||||
</Menu>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col :lg="18" :md="16">
|
||||
<Card class="warp-card" dis-hover style="margin-bottom:100px">
|
||||
<div class="card-title" slot="title">
|
||||
<Icon type="ios-cog"></Icon>功能点
|
||||
</div>
|
||||
<Row>
|
||||
<Table :columns="privilegeTableColumn" :data="privilegeTableData" border></Table>
|
||||
</Row>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span="24">
|
||||
<privilege-form
|
||||
:privilege="formData.privilege"
|
||||
:show="formData.show"
|
||||
:title="formData.title"
|
||||
:typeDisabled="typeDisabled"
|
||||
@closeModal="closeModal"
|
||||
@updateMenuSuccess="getPrivilegeList"
|
||||
></privilege-form>
|
||||
</Col>
|
||||
</Row>
|
||||
</template>
|
||||
<script>
|
||||
import { privilegeApi } from '@/api/privilege';
|
||||
import PrivilegeForm from './components/privilege-form';
|
||||
import { routers } from '@/router/routers';
|
||||
import { PRIVILEGE_TYPE_ENUM } from '@/constants/privilege';
|
||||
|
||||
export default {
|
||||
name: 'SystemPrivilege',
|
||||
components: {
|
||||
PrivilegeForm
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
typeDisabled: true,
|
||||
activeName: 0,
|
||||
scope: 1,
|
||||
formData: {
|
||||
show: false,
|
||||
title: '功能点菜单',
|
||||
privilege: {
|
||||
functionKey: '',
|
||||
functionName: '',
|
||||
menuKey: '',
|
||||
url: 1
|
||||
}
|
||||
},
|
||||
menuTree: [],
|
||||
menusChange: false,
|
||||
menusChangeNum: 0,
|
||||
menuList: [],
|
||||
routerMap: new Map(),
|
||||
privilegeTableData: [],
|
||||
privilegeTableColumn: [
|
||||
{
|
||||
title: '名称',
|
||||
key: 'title'
|
||||
},
|
||||
{
|
||||
title: 'routerKey',
|
||||
key: 'name'
|
||||
},
|
||||
{
|
||||
title: 'url',
|
||||
key: 'url'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
width: 120,
|
||||
align: 'center',
|
||||
className: 'action-hide',
|
||||
render: (h, params) => {
|
||||
return this.$tableAction(h, [
|
||||
{
|
||||
title: '编辑',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'privilege-main-update'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.updatePrivilege(params.row, params.index);
|
||||
}
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.initRouters();
|
||||
},
|
||||
methods: {
|
||||
// 关闭模态框
|
||||
closeModal() {
|
||||
this.formData.show = false;
|
||||
},
|
||||
// 初始化菜单
|
||||
initRouters() {
|
||||
this.resetMenuChange();
|
||||
this.buildPrivilegeTree();
|
||||
},
|
||||
// 获取全部菜单列表
|
||||
async buildPrivilegeTree() {
|
||||
this.$Spin.show();
|
||||
let getMenuListResult = await privilegeApi.getMenuList();
|
||||
let serverMenuList = getMenuListResult.data;
|
||||
let serverMenuMap = new Map();
|
||||
for (let serverMenu of serverMenuList) {
|
||||
serverMenuMap.set(serverMenu.menuKey, serverMenu);
|
||||
}
|
||||
|
||||
let privilegeList = [];
|
||||
let privilegeTree = [];
|
||||
|
||||
for (const router of routers) {
|
||||
//过滤非菜单
|
||||
if (!router.meta.hideInMenu) {
|
||||
this.routerMap.set(router.name, router);
|
||||
let menu = {
|
||||
type: PRIVILEGE_TYPE_ENUM.MENU.value,
|
||||
menuName: router.meta.title,
|
||||
menuKey: router.name,
|
||||
parentKey: null,
|
||||
url: router.path,
|
||||
children: [],
|
||||
sort: 0
|
||||
};
|
||||
privilegeTree.push(menu);
|
||||
privilegeList.push(menu);
|
||||
//判断是否有更新菜单
|
||||
this.hasMenuChange(menu, serverMenuMap);
|
||||
//存在孩子节点,开始递归
|
||||
if (router.children && router.children.length > 0) {
|
||||
this.recursion(router.children, menu, privilegeList, serverMenuMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (privilegeList.length !== serverMenuList.length) {
|
||||
this.menusChange = true;
|
||||
this.menusChangeNum =
|
||||
this.menusChangeNum +
|
||||
Math.abs(privilegeList.length - serverMenuList.length);
|
||||
}
|
||||
|
||||
this.menuTree = privilegeTree;
|
||||
this.menuList = privilegeList;
|
||||
this.$Spin.hide();
|
||||
},
|
||||
|
||||
recursion(children, parentMenu, menuList, serverMenuMap) {
|
||||
for (const router of children) {
|
||||
//过滤非菜单
|
||||
if (!router.meta.hideInMenu) {
|
||||
this.routerMap.set(router.name, router);
|
||||
let menu = {
|
||||
type: PRIVILEGE_TYPE_ENUM.MENU.value,
|
||||
menuName: router.meta.title,
|
||||
menuKey: router.name,
|
||||
parentKey: parentMenu.menuKey,
|
||||
url: router.path,
|
||||
children: [],
|
||||
sort: 0
|
||||
};
|
||||
|
||||
parentMenu.children.push(menu);
|
||||
menuList.push(menu);
|
||||
//判断是否有更新菜单
|
||||
this.hasMenuChange(menu, serverMenuMap);
|
||||
//存在孩子节点,开始递归
|
||||
if (router.children && router.children.length > 0) {
|
||||
this.recursion(router.children, menu, menuList, serverMenuMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// reset菜单有更新
|
||||
resetMenuChange() {
|
||||
this.menusChange = false;
|
||||
this.menusChangeNum = 0;
|
||||
},
|
||||
|
||||
// 菜单有更新
|
||||
hasMenuChange(menu, serverMenuMap) {
|
||||
let isChange = false;
|
||||
let serverMenu = serverMenuMap.get(menu.menuKey);
|
||||
if (serverMenu) {
|
||||
isChange =
|
||||
serverMenu.menuName !== menu.menuName ||
|
||||
serverMenu.menuKey !== menu.menuKey ||
|
||||
serverMenu.parentKey !== menu.parentKey;
|
||||
} else {
|
||||
isChange = true;
|
||||
}
|
||||
|
||||
if (isChange) {
|
||||
this.menusChange = true;
|
||||
this.menusChangeNum = this.menusChangeNum + 1;
|
||||
}
|
||||
},
|
||||
// 菜单批量保存
|
||||
async addBatchSaveMenu() {
|
||||
this.$Spin.show();
|
||||
let result = await privilegeApi.addBatchSaveMenu(this.menuList);
|
||||
this.$Message.success('批量保存成功');
|
||||
this.$Spin.hide();
|
||||
//重新获取数据
|
||||
this.initRouters();
|
||||
},
|
||||
// 编辑功能点
|
||||
updatePrivilege(item, sort) {
|
||||
this.formData.privilege = {
|
||||
functionKey: item.name,
|
||||
functionName: item.title,
|
||||
menuKey: item.parentKey,
|
||||
url: item.url,
|
||||
sort
|
||||
};
|
||||
this.formData.title = item.parentName;
|
||||
this.formData.show = true;
|
||||
},
|
||||
// 查询菜单对应的页面以及功能点
|
||||
async getPrivilegeList(menuKey) {
|
||||
this.$Spin.show();
|
||||
this.formData.show = false;
|
||||
let result = await privilegeApi.queryPrivilegeFunctionList(menuKey);
|
||||
this.$Spin.hide();
|
||||
let datas = result.data;
|
||||
let functionKey = new Map();
|
||||
datas.map(item => {
|
||||
functionKey.set(item.functionKey, item.url);
|
||||
});
|
||||
let privilegeTableData = [];
|
||||
this.privilegeTableData.map(item => {
|
||||
let url = functionKey.get(item.name) || '';
|
||||
item.url = url;
|
||||
privilegeTableData.push(item);
|
||||
});
|
||||
this.privilegeTableData = privilegeTableData;
|
||||
},
|
||||
// 点击菜单事件
|
||||
loadPrivilegeTableData(name) {
|
||||
let router = this.routerMap.get(name);
|
||||
if (!_.isUndefined(router) && router.meta && router.meta.childrenPoints) {
|
||||
this.privilegeTableData = router.meta.childrenPoints.map(e =>
|
||||
Object.assign({}, e, { parentKey: name })
|
||||
);
|
||||
}
|
||||
this.getPrivilegeList(name);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.privilege-badge {
|
||||
background: rgba(45, 140, 240, 0.8);
|
||||
border-radius: 3px;
|
||||
font-size: 8px;
|
||||
color: #fff;
|
||||
line-height: 1;
|
||||
display: inline-block;
|
||||
padding: 0 3px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
</style>
|
||||
545
smart-admin-web/src/views/task/task-list.vue
Normal file
545
smart-admin-web/src/views/task/task-list.vue
Normal file
@@ -0,0 +1,545 @@
|
||||
<template>
|
||||
<div>
|
||||
<Card class="warp-card" dis-hover>
|
||||
<Form class="tools" inline>
|
||||
<FormItem>
|
||||
<Button
|
||||
@click="refresh"
|
||||
icon="md-refresh"
|
||||
type="primary"
|
||||
v-privilege="'task-refresh'"
|
||||
>刷新任务</Button>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button @click="addModal=true" icon="md-add" type="primary" v-privilege="'task-add'">添加任务</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<Tables
|
||||
:columns="columns"
|
||||
:current="pageNum"
|
||||
:loading="loading"
|
||||
:page-size="pageSize"
|
||||
:pageShow="true"
|
||||
:total="pageTotal"
|
||||
:value="data"
|
||||
@on-change="changePage"
|
||||
border
|
||||
show-elevator
|
||||
></Tables>
|
||||
</Card>
|
||||
<!-- 编辑任务 -->
|
||||
<Modal
|
||||
:loading="updateLoading"
|
||||
@on-cancel="cancelUpdate"
|
||||
@on-ok="handleUpdate"
|
||||
title="编辑"
|
||||
v-model="editModal"
|
||||
>
|
||||
<Form :label-width="80" :model="updateItem" :rules="updateValidate" ref="updateRef">
|
||||
<FormItem label="taskBean" prop="taskBean">
|
||||
<Input placeholder="请输入taskBean(必填)" v-model="updateItem.taskBean"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="taskCron" prop="taskCron">
|
||||
<Input placeholder="请输入taskCron(必填)" v-model="updateItem.taskCron"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="任务标题" prop="taskName">
|
||||
<Input placeholder="请输入任务标题(必填)" v-model="updateItem.taskName"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="任务参数" prop="taskParams">
|
||||
<Input placeholder="请输入任务参数(必填)" v-model="updateItem.taskParams"></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
<!-- 添加任务 -->
|
||||
<Modal
|
||||
:loading="saveLoading"
|
||||
@on-cancel="cancelSave"
|
||||
@on-ok="handleSave"
|
||||
title="添加"
|
||||
v-model="addModal"
|
||||
>
|
||||
<Form :label-width="80" :model="saveItem" :rules="saveValidate" ref="saveRef">
|
||||
<FormItem label="taskBean" prop="taskBean">
|
||||
<Input placeholder="请输入taskBean(必填)" v-model="saveItem.taskBean"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="taskCron" prop="taskCron">
|
||||
<Input placeholder="请输入taskCron(必填)" v-model="saveItem.taskCron"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="任务标题" prop="taskName">
|
||||
<Input placeholder="请输入任务标题(必填)" v-model="saveItem.taskName"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="任务参数" prop="taskParams">
|
||||
<Input placeholder="请输入任务参数" v-model="saveItem.taskParams"></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
<!-- 任务日志 -->
|
||||
<Modal :closable="false" :mask-closable="false" title="任务运行日志" v-model="logModal" width="850px">
|
||||
<Row class="log-modal-header" slot="header">
|
||||
<Col :span="18">
|
||||
<span>任务调度日志</span>
|
||||
</Col>
|
||||
</Row>
|
||||
<Tables
|
||||
:columns="logColumns"
|
||||
:current="logPageNum"
|
||||
:page-size="changeLogPageSize"
|
||||
:pageShow="true"
|
||||
:show-elevator="false"
|
||||
:show-sizer="false"
|
||||
:total="logPageTotal"
|
||||
:value="logData"
|
||||
@on-change="logChangePage"
|
||||
style="height: 420px;"
|
||||
v-if="hasLog"
|
||||
></Tables>
|
||||
<div slot="footer">
|
||||
<Button @click="closeLog" type="primary">关闭</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Tables from '@/components/tables';
|
||||
import { taskApi } from '@/api/task-manage';
|
||||
export default {
|
||||
name: 'taskManage',
|
||||
components: {
|
||||
Tables
|
||||
},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
hasLog: false,
|
||||
editModal: false,
|
||||
addModal: false,
|
||||
logModal: false,
|
||||
// 当前所查看的任务Id
|
||||
taskId: '',
|
||||
// table是否loading
|
||||
loading: true,
|
||||
saveLoading: true,
|
||||
updateLoading: true,
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
pageTotal: 0,
|
||||
logPageNum: 1,
|
||||
logPageSize: 6,
|
||||
logPageTotal: 0,
|
||||
updateItem: {
|
||||
taskBean: '',
|
||||
taskCron: '',
|
||||
taskName: '',
|
||||
taskParams: '',
|
||||
taskStatus: ''
|
||||
},
|
||||
saveItem: {
|
||||
taskBean: '',
|
||||
taskCron: '',
|
||||
taskName: '',
|
||||
taskParams: '',
|
||||
taskStatus: ''
|
||||
},
|
||||
// table表头
|
||||
columns: [
|
||||
{
|
||||
title: 'ID',
|
||||
width: 60,
|
||||
key: 'id'
|
||||
},
|
||||
{
|
||||
title: 'taskBean',
|
||||
key: 'taskBean'
|
||||
},
|
||||
{
|
||||
title: 'taskCron',
|
||||
key: 'taskCron'
|
||||
},
|
||||
{
|
||||
title: '任务标题',
|
||||
key: 'taskName'
|
||||
},
|
||||
{
|
||||
title: '任务参数',
|
||||
key: 'taskParams'
|
||||
},
|
||||
{
|
||||
title: '任务状态',
|
||||
key: 'taskStatus',
|
||||
render: (h, params) => {
|
||||
return h('span', params.row.taskStatus === 0 ? '正常' : '暂停');
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
align: 'center',
|
||||
className: 'action-hide',
|
||||
width: 180,
|
||||
render: (h, params) => {
|
||||
return this.$tableAction(h, [
|
||||
{
|
||||
title: '编辑',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'taskUpdate'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.updateItem.taskBean = params.row.taskBean;
|
||||
this.updateItem.id = params.row.id;
|
||||
this.updateItem.taskCron = params.row.taskCron;
|
||||
this.updateItem.taskName = params.row.taskName;
|
||||
this.updateItem.taskParams = params.row.taskParams;
|
||||
this.updateItem.taskStatus = params.row.taskStatus;
|
||||
this.editModal = true;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '删除',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'taskDelete'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.$Modal.confirm({
|
||||
title: '删除',
|
||||
content: '确认删除该条任务么?',
|
||||
onOk: () => {
|
||||
this.deleteTask(params.row.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '立即开始任务',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'taskRun'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.$Modal.confirm({
|
||||
title: '确认',
|
||||
content: '确认立即开始任务么?',
|
||||
onOk: () => {
|
||||
this.controlTask('RUN', params.row.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '暂停任务',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'taskPause'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.$Modal.confirm({
|
||||
title: '确认',
|
||||
content: '确认暂停任务么?',
|
||||
onOk: () => {
|
||||
this.controlTask('PAUSE', params.row.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '恢复任务',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'taskResume'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.$Modal.confirm({
|
||||
title: '确认',
|
||||
content: '确认恢复任务么?',
|
||||
onOk: () => {
|
||||
this.controlTask('RESUME', params.row.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '查看日志',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'taskQueryLog'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.taskId = params.row.id;
|
||||
this.logPageNum = 1;
|
||||
this.getTaskLog();
|
||||
}
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
],
|
||||
// 日志表格表头
|
||||
logColumns: [
|
||||
{
|
||||
type: 'index',
|
||||
width: 60,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '任务名',
|
||||
key: 'taskName'
|
||||
},
|
||||
{
|
||||
title: '任务参数',
|
||||
key: 'taskParams'
|
||||
},
|
||||
{
|
||||
title: '主机IP',
|
||||
key: 'ipAddress'
|
||||
},
|
||||
{
|
||||
title: '处理结果',
|
||||
key: 'processStatus',
|
||||
render: (h, params) => {
|
||||
return h('span', params.row.processStatus === 0 ? '成功' : '失败');
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '处理时长',
|
||||
key: 'processDuration',
|
||||
render: (h, params) => {
|
||||
return h('span', params.row.processDuration + 'ms');
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '失败日志',
|
||||
key: 'processLog',
|
||||
render: (h, params) => {
|
||||
return h(
|
||||
'span',
|
||||
params.row.processLog ? params.row.processLog : '无'
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '运行时间',
|
||||
width: 190,
|
||||
key: 'createTime'
|
||||
}
|
||||
],
|
||||
// table数据
|
||||
data: [],
|
||||
// 日志数据
|
||||
logData: [],
|
||||
updateValidate: {
|
||||
taskBean: [{ required: true, message: '请输入值', trigger: 'blur' }],
|
||||
taskCron: [{ required: true, message: '请输入值', trigger: 'blur' }],
|
||||
taskName: [
|
||||
{ required: true, message: '请输入任务标题', trigger: 'blur' }
|
||||
]
|
||||
},
|
||||
saveValidate: {
|
||||
taskBean: [{ required: true, message: '请输入值', trigger: 'blur' }],
|
||||
taskCron: [{ required: true, message: '请输入值', trigger: 'blur' }],
|
||||
taskName: [
|
||||
{ required: true, message: '请输入任务标题', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.getTaskList();
|
||||
},
|
||||
methods: {
|
||||
// 查询任务调度列表
|
||||
async getTaskList() {
|
||||
try {
|
||||
this.loading = true;
|
||||
let result = await taskApi.getTaskList({
|
||||
pageNum: this.pageNum,
|
||||
pageSize: this.pageSize
|
||||
});
|
||||
this.loading = false;
|
||||
this.data = result.data.list;
|
||||
this.pageTotal = result.data.total;
|
||||
this.pageNum = result.data.pageNum;
|
||||
this.pageSize = result.data.pageSize;
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
// 查询任务运行日志
|
||||
async getTaskLog() {
|
||||
let result = await taskApi.getTaskLog({
|
||||
pageNum: this.logPageNum,
|
||||
pageSize: this.logPageSize,
|
||||
taskId: this.taskId
|
||||
});
|
||||
this.logData = result.data.list;
|
||||
this.logPageTotal = result.data.total;
|
||||
this.logPageNum = result.data.pageNum;
|
||||
this.logPageSize = result.data.pageSize;
|
||||
this.hasLog = true;
|
||||
this.logModal = true;
|
||||
},
|
||||
// 分页
|
||||
changePage(pageNum) {
|
||||
this.pageNum = pageNum;
|
||||
this.getTaskList();
|
||||
},
|
||||
// 分页
|
||||
changePageSize(pageSize) {
|
||||
this.pageNum = 1;
|
||||
this.pageSize = pageSize;
|
||||
this.getTaskList();
|
||||
},
|
||||
// 日志分页
|
||||
changeLogPageSize(pageNum) {
|
||||
this.logPageNum = pageNum;
|
||||
this.getTaskLog();
|
||||
},
|
||||
// 删除任务
|
||||
async deleteTask(id) {
|
||||
let result = await taskApi.deleteTask(id);
|
||||
this.$Message.success('删除任务成功!');
|
||||
this.getTaskList();
|
||||
},
|
||||
// 操作任务
|
||||
async controlTask(type, id) {
|
||||
this.$Spin.show();
|
||||
switch (type) {
|
||||
case 'RUN':
|
||||
await taskApi.updateTaskRun(id);
|
||||
break;
|
||||
case 'PAUSE':
|
||||
await taskApi.updateTaskPause(id);
|
||||
break;
|
||||
case 'RESUME':
|
||||
await taskApi.updateTaskResume(id);
|
||||
break;
|
||||
}
|
||||
this.$Spin.hide();
|
||||
this.$Message.success('操作成功');
|
||||
this.getTaskList();
|
||||
},
|
||||
// 触发更新
|
||||
handleUpdate() {
|
||||
this.$refs['updateRef'].validate(valid => {
|
||||
if (valid) {
|
||||
this.updateTask();
|
||||
} else {
|
||||
this.$Message.success('验证信息不通过');
|
||||
}
|
||||
});
|
||||
},
|
||||
// 修改任务
|
||||
async updateTask() {
|
||||
try {
|
||||
this.updateLoading = true;
|
||||
let result = await taskApi.addOrUpdateTask(this.updateItem);
|
||||
this.updateLoading = false;
|
||||
this.$Message.success('修改成功');
|
||||
this.getTaskList();
|
||||
this.cancelUpdate();
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
this.updateLoading = false;
|
||||
}
|
||||
},
|
||||
// 保存任务
|
||||
handleSave() {
|
||||
try {
|
||||
this.$refs['saveRef'].validate(valid => {
|
||||
this.saveLoading = true;
|
||||
if (valid) {
|
||||
this.saveTask();
|
||||
} else {
|
||||
this.saveLoading = false;
|
||||
this.$nextTick(() => {
|
||||
this.saveLoading = true;
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
this.saveLoading = false;
|
||||
}
|
||||
},
|
||||
// 保存任务
|
||||
async saveTask() {
|
||||
try {
|
||||
let result = await taskApi.addOrUpdateTask(this.saveItem);
|
||||
this.saveLoading = false;
|
||||
this.$Message.success('添加成功');
|
||||
this.getTaskList();
|
||||
this.cancelSave();
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
this.saveLoading = false;
|
||||
}
|
||||
},
|
||||
// 取消保存
|
||||
cancelSave() {
|
||||
this.saveItem = {};
|
||||
// 清空form规则检查
|
||||
this.$refs['saveRef'].resetFields();
|
||||
this.addModal = false;
|
||||
},
|
||||
// 取消修改
|
||||
cancelUpdate() {
|
||||
this.updateItem = {};
|
||||
// 清空form规则检查
|
||||
this.$refs['updateRef'].resetFields();
|
||||
this.editModal = false;
|
||||
},
|
||||
// 关闭日志
|
||||
closeLog() {
|
||||
this.logData = [];
|
||||
this.logPageNum = 1;
|
||||
this.hasLog = false;
|
||||
this.logModal = false;
|
||||
},
|
||||
// 刷新
|
||||
refresh() {
|
||||
this.pageNum = 1;
|
||||
this.getTaskList();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.log-modal-header {
|
||||
height: 25px;
|
||||
line-height: 25px;
|
||||
font-size: 14px;
|
||||
color: #17233d;
|
||||
font-weight: bold;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.log-modal-header-btn-group {
|
||||
text-align: right;
|
||||
button {
|
||||
margin: 0 5px;
|
||||
span {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
185
smart-admin-web/src/views/user-log/user-login-log.vue
Normal file
185
smart-admin-web/src/views/user-log/user-login-log.vue
Normal file
@@ -0,0 +1,185 @@
|
||||
<template>
|
||||
<div>
|
||||
<Card class="warp-card" dis-hover>
|
||||
<Form
|
||||
:model="searchform"
|
||||
class="tools"
|
||||
inline
|
||||
ref="searchform"
|
||||
v-privilege="'user-login-log-search'"
|
||||
>
|
||||
<FormItem prop="startDate">
|
||||
<DatePicker
|
||||
placeholder="开始日期"
|
||||
style="width: 200px"
|
||||
type="date"
|
||||
v-model="searchform.startDate"
|
||||
></DatePicker>
|
||||
</FormItem>
|
||||
<FormItem prop="endDate">
|
||||
<DatePicker
|
||||
placeholder="结束日期"
|
||||
style="width: 200px"
|
||||
type="date"
|
||||
v-model="searchform.endDate"
|
||||
></DatePicker>
|
||||
</FormItem>
|
||||
<FormItem prop="userName">
|
||||
<Input placeholder="请输入用户名" type="text" v-model="searchform.userName"></Input>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<ButtonGroup>
|
||||
<Button @click="search" icon="ios-search" type="primary">查询</Button>
|
||||
<Button @click="reset" icon="md-refresh" type="default">重置</Button>
|
||||
</ButtonGroup>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<Table :columns="columns" :data="data" :loading="loading"></Table>
|
||||
<Page
|
||||
:current="searchform.pageNum"
|
||||
:page-size="searchform.pageSize"
|
||||
:page-size-opts="[10, 20, 30, 50, 100]"
|
||||
:total="pageTotal"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
show-elevator
|
||||
show-sizer
|
||||
show-total
|
||||
style="margin:24px 0;text-align:right;"
|
||||
></Page>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { userLogApi } from '@/api/user-log';
|
||||
export default {
|
||||
name: 'UserLoginLog',
|
||||
components: {},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
searchform: {
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
searchCount: true,
|
||||
sort: false,
|
||||
userName: ''
|
||||
},
|
||||
pageTotal: 0,
|
||||
// table表头
|
||||
columns: [
|
||||
{
|
||||
title: '用户名称',
|
||||
key: 'userName'
|
||||
},
|
||||
{
|
||||
title: '浏览器',
|
||||
key: 'remoteBrowser'
|
||||
},
|
||||
{
|
||||
title: '操作系统',
|
||||
key: 'remoteOs'
|
||||
},
|
||||
{
|
||||
title: 'Ip',
|
||||
key: 'remoteIp'
|
||||
},
|
||||
{
|
||||
title: '用户端口',
|
||||
key: 'remotePort'
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'createTime'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
align: 'center',
|
||||
className: 'action-hide',
|
||||
render: (h, param) => {
|
||||
return this.$tableAction(h, [
|
||||
{
|
||||
title: '删除',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'user-login-log-delete'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.$Modal.confirm({
|
||||
title: '友情提醒',
|
||||
content: '确定要删除吗?',
|
||||
onOk: () => {
|
||||
this.deleteLog(param.row.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
],
|
||||
// table数据
|
||||
data: []
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
filters: {},
|
||||
created() {},
|
||||
mounted() {
|
||||
this.getUserLoginLogPage();
|
||||
},
|
||||
methods: {
|
||||
// 查询用户登录日志
|
||||
async getUserLoginLogPage() {
|
||||
try {
|
||||
this.loading = true;
|
||||
let result = await userLogApi.getUserLoginLogPage(this.searchform);
|
||||
this.loading = false;
|
||||
this.data = result.data.list;
|
||||
this.pageTotal = result.data.total;
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
// 翻页
|
||||
changePage(pageNum) {
|
||||
this.searchform.pageNum = pageNum;
|
||||
this.getUserLoginLogPage();
|
||||
},
|
||||
// 改变一页展示数
|
||||
changePageSize(pageSize) {
|
||||
this.searchform.pageNum = 1;
|
||||
this.searchform.pageSize = pageSize;
|
||||
this.getUserLoginLogPage();
|
||||
},
|
||||
// 搜索
|
||||
search() {
|
||||
this.searchform.pageNum = 1;
|
||||
this.getUserLoginLogPage();
|
||||
},
|
||||
// 重置
|
||||
reset() {
|
||||
this.$refs.searchform.resetFields();
|
||||
this.search();
|
||||
},
|
||||
// 删除日志
|
||||
async deleteLog(id) {
|
||||
this.$Spin.show();
|
||||
await userLogApi.deleteUserLoginLog(id);
|
||||
this.$Spin.hide();
|
||||
this.$Message.success('删除成功');
|
||||
this.getUserLoginLogPage();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
252
smart-admin-web/src/views/user-log/user-operate-log.vue
Normal file
252
smart-admin-web/src/views/user-log/user-operate-log.vue
Normal file
@@ -0,0 +1,252 @@
|
||||
<template>
|
||||
<div>
|
||||
<Card class="warp-card" dis-hover>
|
||||
<Form
|
||||
:model="searchform"
|
||||
class="tools"
|
||||
inline
|
||||
ref="searchform"
|
||||
v-privilege="'user-operate-log-search'"
|
||||
>
|
||||
<FormItem prop="startDate">
|
||||
<DatePicker
|
||||
placeholder="开始日期"
|
||||
style="width: 200px"
|
||||
type="date"
|
||||
v-model="searchform.startDate"
|
||||
></DatePicker>
|
||||
</FormItem>
|
||||
<FormItem prop="endDate">
|
||||
<DatePicker
|
||||
placeholder="结束日期"
|
||||
style="width: 200px"
|
||||
type="date"
|
||||
v-model="searchform.endDate"
|
||||
></DatePicker>
|
||||
</FormItem>
|
||||
<FormItem prop="userName">
|
||||
<Input placeholder="请输入用户名" type="text" v-model="searchform.userName"></Input>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<ButtonGroup>
|
||||
<Button @click="search" icon="ios-search" type="primary">查询</Button>
|
||||
<Button @click="reset" icon="md-refresh" type="default">重置</Button>
|
||||
</ButtonGroup>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<Table :columns="columns" :data="data" :loading="tableLoading" :total="pageTotal"></Table>
|
||||
<Page
|
||||
:current="searchform.pageNum"
|
||||
:page-size="searchform.pageSize"
|
||||
:page-size-opts="[10, 20, 30, 50, 100]"
|
||||
:total="pageTotal"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
show-elevator
|
||||
show-sizer
|
||||
show-total
|
||||
style="margin:24px 0;text-align:right;"
|
||||
></Page>
|
||||
</Card>
|
||||
|
||||
<Modal title="日志详情" v-model="detailModal">
|
||||
<Form :label-width="80" :model="logDetail">
|
||||
<FormItem label="用户名称:">{{logDetail.userName}}</FormItem>
|
||||
<FormItem label="用户类型:">{{logDetail.userType?'前台':'后台'}}</FormItem>
|
||||
<FormItem label="操作模块:">{{logDetail.module}}</FormItem>
|
||||
<FormItem label="操作内容:">{{logDetail.content}}</FormItem>
|
||||
<FormItem label="请求方法:">{{logDetail.method}}</FormItem>
|
||||
<FormItem label="请求路径:">{{logDetail.url}}</FormItem>
|
||||
<FormItem label="请求参数:">{{logDetail.param}}</FormItem>
|
||||
<FormItem label="请求结果:">{{logDetail.result?'成功':'失败'}}</FormItem>
|
||||
<FormItem label="失败原因:">
|
||||
<div style="max-height:120px;overflow-y:scroll;">{{logDetail.failReason}}</div>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { userLogApi } from '@/api/user-log';
|
||||
export default {
|
||||
name: 'UserOperateLog',
|
||||
components: {},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
tableLoading: false,
|
||||
searchform: {
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
searchCount: true,
|
||||
sort: false,
|
||||
userName: ''
|
||||
},
|
||||
pageTotal: 0,
|
||||
// table表头
|
||||
columns: [
|
||||
{
|
||||
title: '用户名称',
|
||||
key: 'userName',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '操作模块',
|
||||
key: 'module',
|
||||
tooltip: true,
|
||||
width: 180
|
||||
},
|
||||
{
|
||||
title: '操作内容',
|
||||
key: 'content',
|
||||
tooltip: true,
|
||||
width: 260
|
||||
},
|
||||
{
|
||||
title: '请求方法',
|
||||
key: 'method',
|
||||
tooltip: true,
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
title: '请求路径',
|
||||
key: 'url',
|
||||
tooltip: true,
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
title: '请求参数',
|
||||
key: 'param',
|
||||
tooltip: true,
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
title: '请求结果',
|
||||
key: 'result',
|
||||
width: 100,
|
||||
render: (h, param) => {
|
||||
if (param.row.result) {
|
||||
return h('div', '成功');
|
||||
}
|
||||
return h('div', '失败');
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '-'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 160,
|
||||
align: 'center',
|
||||
className: 'action-hide',
|
||||
fixed: 'right',
|
||||
render: (h, param) => {
|
||||
return this.$tableAction(h, [
|
||||
{
|
||||
title: '详情',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'user-operate-log-detail'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.showLogDetail(param.row.id);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '删除',
|
||||
directives: [
|
||||
{
|
||||
name: 'privilege',
|
||||
value: 'user-operate-log-delete'
|
||||
}
|
||||
],
|
||||
action: () => {
|
||||
this.$Modal.confirm({
|
||||
title: '友情提醒',
|
||||
content: '确定要删除吗?',
|
||||
onOk: () => {
|
||||
this.deleteLog(param.row.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
],
|
||||
// table数据
|
||||
data: [],
|
||||
detailModal: false,
|
||||
logDetail: {}
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
filters: {},
|
||||
mounted() {
|
||||
this.getUserOperateLogPage();
|
||||
},
|
||||
methods: {
|
||||
// 查询用户操作日志
|
||||
async getUserOperateLogPage() {
|
||||
this.tableLoading = true;
|
||||
try {
|
||||
let result = await userLogApi.getUserOperateLogPage(this.searchform);
|
||||
this.tableLoading = false;
|
||||
this.data = result.data.list;
|
||||
this.pageTotal = result.data.total;
|
||||
} catch (e) {
|
||||
//TODO zhuoda sentry
|
||||
console.error(e);
|
||||
this.tableLoading = false;
|
||||
}
|
||||
},
|
||||
changePage(pageNum) {
|
||||
this.searchform.pageNum = pageNum;
|
||||
this.getUserOperateLogPage();
|
||||
},
|
||||
changePageSize(pageSize) {
|
||||
this.searchform.pageNum = 1;
|
||||
this.searchform.pageSize = pageSize;
|
||||
this.getUserOperateLogPage();
|
||||
},
|
||||
// 搜索
|
||||
search() {
|
||||
this.searchform.pageNum = 1;
|
||||
this.getUserOperateLogPage();
|
||||
},
|
||||
reset() {
|
||||
this.$refs.searchform.resetFields();
|
||||
this.search();
|
||||
},
|
||||
// 获取并查看详情
|
||||
async showLogDetail(id) {
|
||||
this.$Spin.show();
|
||||
let res = await userLogApi.detailUserOperateLog(id);
|
||||
this.$Spin.hide();
|
||||
this.logDetail = res.data;
|
||||
this.detailModal = true;
|
||||
},
|
||||
// 删除日志
|
||||
async deleteLog(id) {
|
||||
this.$Spin.show();
|
||||
await userLogApi.deleteUserOperateLog(id);
|
||||
this.$Spin.hide();
|
||||
this.$Message.success('删除成功');
|
||||
this.getUserOperateLogPage();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.ivu-form-item {
|
||||
word-break: break-word;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user