组织机构

This commit is contained in:
吕金泽
2022-01-09 22:13:45 +08:00
parent 02cd4e7986
commit 33f76b8803
16 changed files with 759 additions and 150 deletions
@@ -23,7 +23,7 @@
/>
<div v-else-if="col.type == 'btns'">
<template v-for="btn in col.btns">
<el-button v-if="btn.if === undefined ? true : btn.if(scope.row)" :key="btn.title" v-permission="btn.permission" :type="btn.type" :size="btn.size || 'mini'" :class="btn.class" @click="btn.click(scope.row, scope.$index)">
<el-button v-if="btn.if === undefined ? true : btn.if(scope.row)" :icon="btn.icon" :key="btn.title" v-permission="btn.permission" :type="btn.type" :size="btn.size || 'mini'" :class="btn.class" @click="btn.click(scope.row, scope.$index)">
{{ btn.title }}
</el-button>
</template>
+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1641720023979" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15481" width="240" height="240" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M960 1024h-320v-384h128V576H256v64h128v384H0v-384h128V448h320V384H320V0h384v384H576v64h320v192h128v384h-64zM128 896h128v-128H128v128zM576 128H448v128h128V128z m320 640h-128v128h128v-128z" p-id="15482"></path></svg>

After

Width:  |  Height:  |  Size: 592 B

+3
View File
@@ -22,6 +22,9 @@ Vue.use(elDragDialog)
import common from '@/scripts/common'
Vue.prototype.$common = common
import treeTable from '@/scripts/treeTable'
Vue.prototype.$treeTable = treeTable
import request from '@/scripts/request'
Vue.prototype.$request = request
Vue.prototype.$post = (url, data) => request.post(url, data, {
+82
View File
@@ -0,0 +1,82 @@
import common from "@/scripts/common";
const treeTable = {}
treeTable.isChildren = (children, id) => {
var result = false
for(var i in children) {
var chi = children[i]
if(chi.id == id){
result = true
}
if(chi.children && children.length > 0){
if(treeTable.isChildren(chi.children, id)){
result = true
}
}
}
return result
}
treeTable.queryChildren = (children, id) => {
var result = []
for(var i in children){
var chi = children[i]
if(chi.id == id){
if(chi.children && chi.children.length > 0){
result = chi.children
}
}else{
var qc = treeTable.queryChildren(chi.children, id)
if(qc.length > 0){
result = qc
}
}
}
return result
}
treeTable.genTree = (children) => {
var treeData = []
for(var i in children){
var chi = {}
chi.label = children[i].name
chi.id = children[i].id
if(children[i].children && children[i].children.length > 0){
chi.children = treeTable.genTree(children[i].children)
}
treeData.push(chi)
}
return treeData
}
treeTable.recursionSearch = (fields, data, text) => {
var searchData = []
for(var i in data){
var treeNode = data[i]
var children = treeNode.children
if(children && children.length > 0){
var childrenSearch = treeTable.recursionSearch(fields, children, text)
treeNode.children = childrenSearch && childrenSearch.length > 0 ? childrenSearch : treeNode.children
treeTable.treeNodeReplace(fields, searchData, treeNode, text, childrenSearch)
}else{
treeTable.treeNodeReplace(fields, searchData, treeNode, text)
}
}
return searchData
}
treeTable.treeNodeReplace = (fields, searchData, treeNode, text, childrenSearch) => {
var exist = false
fields.forEach((f) => {
if(treeNode[f] && treeNode[f].indexOf(text) != -1){
treeNode[f] = treeNode[f].replace(text, `<font color="#FAA353">${text}</font>`)
exist = true
}
})
if(exist || (childrenSearch && childrenSearch.length > 0)){
searchData.push(treeNode)
}
}
export default treeTable
+94 -102
View File
@@ -1,3 +1,9 @@
<style>
.el-input-number .el-input__inner{
text-align: left;
}
</style>
<template>
<div class="app-container">
@@ -19,17 +25,18 @@
<el-button class="filter-item" style="margin-bottom:10px;" type="primary" icon="el-icon-edit" @click="addSubMenu('0')">
添加菜单
</el-button>
<el-button type="primary" icon="el-icon-sort" plain @click="expand">展开/折叠</el-button>
</el-row>
<pd-table ref="table" v-bind="tableOptions" v-if="menuData && menuData.length > 0" />
<pd-table ref="table" v-bind="tableOptions" v-if="menuData && menuData.length > 0 && refreshTable" />
<pd-dialog ref="menuFormDialog" width="800px" :title="textMap[dialogStatus]" @confirm-click="save()">
<pd-dialog ref="menuFormDialog" width="1050px" :title="textMap[dialogStatus]" @confirm-click="save()">
<template #content>
<el-form ref="dataForm" :rules="rules" :model="temp" label-position="right" label-width="80px" style="width: 600px; margin-left:50px;">
<el-form ref="dataForm" :rules="rules" :model="temp" label-position="right" label-width="80px" style="width: 900px; margin-left:50px;">
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="菜单类型" prop="type">
<el-radio-group v-model="temp.type" size="small">
<el-radio-group v-model="menuType" size="small">
<el-radio-button label="menu">菜单</el-radio-button>
<el-radio-button label="button">按钮</el-radio-button>
</el-radio-group>
@@ -44,17 +51,22 @@
<el-form-item label="菜单名称" prop="name">
<el-input v-model="temp.name" />
</el-form-item>
<el-form-item label="菜单链接" prop="url" v-if="temp.type == 'menu'">
<el-form-item label="菜单链接" prop="url" v-if="menuType == 'menu'">
<el-input v-model="temp.url" />
</el-form-item>
<el-form-item label="权限标识" prop="permission">
<el-form-item label="权限标识" prop="permission" v-if="menuType == 'button'">
<el-input v-model="temp.permission" />
</el-form-item>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="图标" prop="icon" v-if="temp.type == 'menu'">
<el-col :span="6">
<el-form-item label="排序" prop="sort">
<el-input-number v-model="temp.sort" controls-position="right" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="选择图标" prop="icon" v-if="menuType == 'menu'">
<a @click="openIcons">
<el-input placeholder="请选择图标" v-model="temp.icon" class="input-with-select">
<el-input v-model="temp.icon" class="input-with-select">
<el-button class="icon-btn" slot="append">
<i v-html="generateIconCode(temp.icon)"></i>
</el-button>
@@ -62,21 +74,20 @@
</a>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="排序" prop="sort">
<el-input-number v-model="temp.sort" controls-position="right" />
<el-col :span="6">
<el-form-item label="菜单显示" v-if="menuType == 'menu'">
<el-radio-group v-model="temp.isShow" size="small">
<el-radio-button label="1">显示</el-radio-button>
<el-radio-button label="0">不显示</el-radio-button>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="是否显示" v-if="temp.type == 'menu'">
<el-switch v-model="temp.isShow" :active-value="1" :inactive-value="0"></el-switch>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否缓存" v-if="temp.type == 'menu'">
<el-switch v-model="temp.keepAlive" :active-value="1" :inactive-value="0"></el-switch>
<el-col :span="6">
<el-form-item label="路由缓存" v-if="menuType == 'menu'">
<el-radio-group v-model="temp.keepAlive" size="small">
<el-radio-button label="1">缓存</el-radio-button>
<el-radio-button label="0">不缓存</el-radio-button>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
@@ -102,6 +113,8 @@ export default {
components: { MenuIcons, Treeselect },
data() {
return {
menuType: 'menu',
refreshTable: true,
menuData: [],
menuTree: [],
searchValue: '',
@@ -144,9 +157,44 @@ export default {
},
{
field: 'sort',
title: '序',
title: '序',
width: 60
},
{
title: '排序',
type: 'btns',
width: 150,
btns: [
{
title: '上移',
type: 'text',
icon: 'el-icon-sort-up',
click: (row) => {
this.$get('menu/sort/up',{
id: row.id,
pid: row.pid,
sort: row.sort
}).then(() => {
this.reloadTable()
})
}
},
{
title: '下移',
type: 'text',
icon: 'el-icon-sort-down',
click: (row) => {
this.$get('menu/sort/down',{
id: row.id,
pid: row.pid,
sort: row.sort
}).then(() => {
this.reloadTable()
})
}
}
]
},
{
field: 'isShow',
title: '是否显示',
@@ -174,13 +222,14 @@ export default {
{
title: '操作',
type: 'btns',
width: 262,
width: 260,
fixed: 'right',
align: 'left',
btns: [
{
title: '添加下级菜单',
type: 'text',
icon: 'el-icon-plus',
click: (row) => {
this.addSubMenu(row.id)
}
@@ -188,6 +237,7 @@ export default {
{
title: '编辑',
type: 'text',
icon: 'el-icon-edit',
click: (row) => {
this.handleUpdate(row)
}
@@ -195,6 +245,7 @@ export default {
{
title: '删除',
type: 'text',
icon: 'el-icon-delete',
click: (row) => {
this.$common.handleDelete({
url: 'menu/delete',
@@ -227,7 +278,7 @@ export default {
this.reloadTable()
},
watch: {
'temp.type'(type) {
menuType(type) {
for (var t in this.getTemp()) {
if(t != 'type'){
this.temp[t] = row[t]
@@ -243,95 +294,29 @@ export default {
this.menuTree = [{
label: '根节点',
id: '0',
children: this.genMenuTree(this.menuData)
children: this.$treeTable.genMenuTree(this.menuData)
}]
}
},
methods: {
isChildren(children, id) {
var result = false
for(var i in children) {
var chi = children[i]
if(chi.id == id){
result = true
}
if(chi.children && children.length > 0){
if(this.isChildren(chi.children, id)){
result = true
}
}
}
return result
},
queryChildren(children, id) {
var result = []
for(var i in children){
var chi = children[i]
if(chi.id == id){
if(chi.children && chi.children.length > 0){
result = chi.children
}
}else{
var qc = this.queryChildren(chi.children, id)
if(qc.length > 0){
result = qc
}
}
}
return result
},
genMenuTree(children) {
var menuTree = []
for(var i in children){
var chi = {}
chi.label = children[i].name
chi.id = children[i].id
if(children[i].children && children[i].children.length > 0){
chi.children = this.genMenuTree(children[i].children)
}
menuTree.push(chi)
}
return menuTree
expand(){
this.refreshTable = false
this.tableOptions.el["default-expand-all"] = !this.tableOptions.el["default-expand-all"]
this.$nextTick(() => {
this.refreshTable = true
})
},
searchMenu() {
var _this = this
clearTimeout(this.searchTimeout)
this.searchTimeout = setTimeout(() => {
if(_this.searchValue){
_this.$set(_this.tableOptions, 'data', _this.recursionSearch(_this.$common.copyNew(_this.menuData), _this.searchValue))
_this.$set(_this.tableOptions, 'data', _this.$treeTable.recursionSearch(['name', 'url', 'permission'], _this.$common.copyNew(_this.menuData), _this.searchValue))
}else{
_this.$set(_this.tableOptions, 'data', _this.menuData)
}
},1000)
},
recursionSearch(data, text){
var searchData = []
for(var i in data){
var treeNode = data[i]
var children = treeNode.children
if(children && children.length > 0){
var childrenSearch = this.recursionSearch(children, text)
treeNode.children = childrenSearch && childrenSearch.length > 0 ? childrenSearch : treeNode.children
this.treeNodeReplace(searchData, treeNode, text, childrenSearch)
}else{
this.treeNodeReplace(searchData, treeNode, text)
}
}
return searchData
},
treeNodeReplace(searchData, treeNode, text, childrenSearch){
var exist = false
var fields = ['name', 'url', 'permission']
fields.forEach((f) => {
if(treeNode[f] && treeNode[f].indexOf(text) != -1){
treeNode[f] = treeNode[f].replace(text, `<font color="#FAA353">${text}</font>`)
exist = true
}
})
if(exist || (childrenSearch && childrenSearch.length > 0)){
searchData.push(treeNode)
}
},
generateIconCode(symbol) {
return `<svg style="width: 20px;height: 20px;fill: #999" aria-hidden="true" class="svg-icon disabled"><use href="#icon-${symbol}"></use></svg>`
},
@@ -353,7 +338,6 @@ export default {
isShow: 1,
pid: '',
icon: '',
type: 'menu',
keepAlive: 1
}
},
@@ -388,7 +372,7 @@ export default {
})
return
}
if(this.isChildren(this.queryChildren(this.menuData, this.temp.id), this.temp.pid)){
if(this.$treeTable.isChildren(this.$treeTable.queryChildren(this.menuData, this.temp.id), this.temp.pid)){
this.$notify({
title: '失败',
message: '上级菜单不能选当前菜单子级',
@@ -397,6 +381,14 @@ export default {
})
return
}
if(this.menuType == 'menu'){
this.temp.permission = ''
}else{
this.temp.isShow = 1
this.temp.keepAlive = 1
this.temp.icon = ''
this.temp.url = ''
}
this.$post('menu/save', this.temp).then(() => {
this.reloadTable()
this.$refs.menuFormDialog.hide()
@@ -420,7 +412,7 @@ export default {
for (var t in this.temp) {
this.temp[t] = row[t]
}
this.temp.type = this.temp.url ? 'menu' : 'button'
this.menuType = this.temp.url ? 'menu' : 'button'
this.temp.name = this.temp.name.replaceAll(/<font.*?>(.*?)<\/font>/g,'$1')
this.dialogStatus = 'update'
this.$refs.menuFormDialog.show()
@@ -1,24 +1,69 @@
<style>
.el-input-number .el-input__inner{
text-align: left;
}
</style>
<template>
<div class="app-container">
<el-button class="filter-item" style="margin-bottom:10px;" type="primary" icon="el-icon-edit" @click="addSubMenu('0')">
添加组织机构
</el-button>
<div class="filter-container">
<el-form :inline="true">
<el-form-item label="机构搜索">
<el-input v-model="searchValue" @input="searchOffice" placeholder="机构名称、链接、权限标识" style="width: 200px"></el-input>
</el-form-item>
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="searchOffice">
搜索
</el-button>
<el-button class="filter-item" icon="el-icon-delete" @click="() => { this.searchValue = ''; searchOffice() }">
清空
</el-button>
</el-form>
</div>
<pd-table ref="table" v-bind="tableOptions" />
<el-row style="margin-bottom: 5px">
<el-button class="filter-item" style="margin-bottom:10px;" type="primary" icon="el-icon-edit" @click="addSubOffice('0')">
添加机构
</el-button>
<el-button type="primary" icon="el-icon-sort" plain @click="expand">展开/折叠</el-button>
</el-row>
<pd-dialog :visible.sync="dialogFormVisible" width="600px" @confirm-click="$refs.dataForm.save()">
<pd-table ref="table" v-bind="tableOptions" v-if="officeData && officeData.length > 0 && refreshTable" />
<pd-dialog ref="officeFormDialog" width="1050px" :title="textMap[dialogStatus]" @confirm-click="save()">
<template #content>
<el-form ref="dataForm" :rules="rules" :model="temp" label-position="left" label-width="100px" style="width: 400px; margin-left:50px;">
<el-form-item label="名称" prop="name">
<el-input v-model="temp.name" />
</el-form-item>
<el-form-item label="类型" prop="type">
<pd-select v-model="temp.type" type="office_type" width="100%" />
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input v-model="temp.sort" />
</el-form-item>
<el-form ref="dataForm" :rules="rules" :model="temp" label-position="right" label-width="80px" style="width: 900px; margin-left:50px;">
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="机构类型" prop="type">
<pd-select v-model="temp.type" type="office_type" width="100%" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="上级机构" prop="pid">
<treeselect v-model="temp.pid" :options="officeTree" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="机构名称" prop="name">
<el-input v-model="temp.name" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="机构编码" prop="code">
<el-input v-model="temp.code" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="6">
<el-form-item label="排序" prop="sort">
<el-input-number v-model="temp.sort" controls-position="right" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
</pd-dialog>
@@ -27,61 +72,106 @@
</template>
<script>
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
export default {
components: { Treeselect },
data() {
return {
refreshTable: true,
officeData: [],
officeTree: [],
searchValue: '',
tableOptions: {
el: {
'default-expand-all': true,
'tree-props': { children: 'children' },
'tree-props': { children: 'children', hasChildren: 'hasChildren' },
'row-key': 'id'
},
showNo: false,
data: [],
updateStr: '',
page: false,
cols: [
{
field: 'name',
title: '名称',
width: '400',
align: 'left'
title: '机构名称',
align: 'left',
type: 'html'
},
{
field: 'type',
title: '类型',
dictType: 'office_type',
width: '250',
align: 'left'
field: 'code',
title: '机构编码',
width: 300,
align: 'left',
type: 'html'
},
{
field: 'sort',
title: '序',
title: '序',
width: 60
},
{
title: '排序',
type: 'btns',
width: 150,
btns: [
{
title: '上移',
type: 'text',
icon: 'el-icon-sort-up',
click: (row) => {
this.$get('office/sort/up',{
id: row.id,
pid: row.pid,
sort: row.sort
}).then(() => {
this.reloadTable()
})
}
},
{
title: '下移',
type: 'text',
icon: 'el-icon-sort-down',
click: (row) => {
this.$get('office/sort/down',{
id: row.id,
pid: row.pid,
sort: row.sort
}).then(() => {
this.reloadTable()
})
}
}
]
},
{
title: '操作',
type: 'btns',
width: 260,
fixed: 'right',
align: 'left',
btns: [
{
title: '添加下级',
type: 'primary',
title: '添加下级机构',
type: 'text',
icon: 'el-icon-plus',
click: (row) => {
this.addSubMenu(row.id)
this.addSubOffice(row.id)
}
},
{
title: '编辑',
type: 'primary',
type: 'text',
icon: 'el-icon-edit',
click: (row) => {
this.handleUpdate(row)
}
},
{
title: '删除',
type: 'danger',
type: 'text',
icon: 'el-icon-delete',
click: (row) => {
this.$common.handleDelete({
url: 'office/delete',
@@ -101,33 +191,71 @@ export default {
create: '添加'
},
temp: this.getTemp(),
listConfigDialogVisible: false,
formConfigDialogVisible: false,
rules: {
name: [{ required: true, message: '请输入名称', trigger: 'change' }],
type: [{ required: true, message: '请选择类型', trigger: 'change' }]
}
pid: [{ required: true, message: '请选择上级机构', trigger: 'change' }],
name: [{ required: true, message: '请输入机构名称', trigger: 'change' }]
},
searchTimeout: ''
}
},
created() {
mounted() {
this.reloadTable()
},
watch: {
officeData() {
this.officeTree = [{
label: '根节点',
id: '0',
children: this.$treeTable.genTree(this.officeData)
}]
}
},
methods: {
expand(){
this.refreshTable = false
this.tableOptions.el["default-expand-all"] = !this.tableOptions.el["default-expand-all"]
this.$nextTick(() => {
this.refreshTable = true
})
},
searchOffice() {
var _this = this
clearTimeout(this.searchTimeout)
this.searchTimeout = setTimeout(() => {
if(_this.searchValue){
_this.$set(_this.tableOptions, 'data', _this.$treeTable.recursionSearch(['name', 'code'], _this.$common.copyNew(_this.officeData), _this.searchValue))
}else{
_this.$set(_this.tableOptions, 'data', _this.officeData)
}
},1000)
},
getTemp() {
return {
id: '',
name: '',
type: '',
sort: 0,
pid: ''
pid: '',
type: '',
code: ''
}
},
resetTemp() {
this.temp = this.getTemp()
},
addSubMenu(id) {
getSort() {
this.$get('office/sort', { pid: this.temp.pid }).then(res => {
this.temp.sort = res.data
})
},
addSubOffice(id) {
this.resetTemp()
this.temp.pid = id
this.temp.id = this.$common.uuid()
this.getSort()
this.dialogStatus = 'create'
this.dialogFormVisible = true
this.$refs.officeFormDialog.show()
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
@@ -135,9 +263,27 @@ export default {
save() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
if(this.temp.pid == this.temp.id){
this.$notify({
title: '失败',
message: '上级机构不能选当前机构',
type: 'error',
duration: 2000
})
return
}
if(this.$treeTable.isChildren(this.$treeTable.queryChildren(this.officeData, this.temp.id), this.temp.pid)){
this.$notify({
title: '失败',
message: '上级机构不能选当前机构子级',
type: 'error',
duration: 2000
})
return
}
this.$post('office/save', this.temp).then(() => {
this.reloadTable()
this.dialogFormVisible = false
this.$refs.officeFormDialog.hide()
this.$notify({
title: '成功',
message: (this.dialogStatus === 'create' ? '创建' : '修改') + '成功',
@@ -149,16 +295,18 @@ export default {
})
},
reloadTable() {
this.$get('office/list').then(res => {
this.$set(this.tableOptions, 'data', this.$common.handlerTreeData(res.data, 'id', 'pid', 'sort', '0'))
this.$get('office/tree').then(res => {
this.officeData = res.data.list
this.$set(this.tableOptions, 'data', this.officeData)
})
},
handleUpdate(row) {
for (var t in this.temp) {
this.temp[t] = row[t]
}
this.temp.name = this.temp.name.replaceAll(/<font.*?>(.*?)<\/font>/g,'$1')
this.dialogStatus = 'update'
this.dialogFormVisible = true
this.$refs.officeFormDialog.show()
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})