父页面(左右结构布局,构成:表格和弹窗组件、左边目录)
<template>
<div style="height:100%;display:flex">
<div class="leftshuxing">
<left-list @cliitem="handleitem" @reload="reload" class="leftlist"></left-list>
</div>
<div class="rightdrig">
<div class="gr-datagrid-notitle">
<data-grid ref="dataGrid" @editFun="editFun" @deleteFun="deleteFun" @addFun="addFun" />
</div>
<gr-dialog :dialogVisible.sync="dialogVisible" :dialogOptions="dialogOptions" :dialogContentComponent="dialogContentComponent" :data="dialogData" :show="show" />
</div>
</div>
</template>
<script>
import dataGrid from '@/components/grid/zzqx-gn/index.vue'
import grDialog from '@/components/common/dialog/index.vue'
import leftList from '@/components/grid/zzqx-gn/leftList.vue'
import { mapState } from 'vuex'
export default {
data() {
return {
dialogOptions: {},
dialogVisible: false,
dialogContentComponent: null,
dialogData: {},
show: true
}
},
components: {
dataGrid,
grDialog,
leftList
},
computed: mapState(['chooseId', 'chooseData']),
methods: {
reload(prame) {
this.$refs.dataGrid.load(prame)
},
addFun(data) {
this.show = true
this.dialogVisible = true
this.dialogOptions = {
width: '700px',
title: '增加功能',
saveBtn: '提交'
}
this.dialogContentComponent = () =>
import('@/components/dialog/zzqx-gn/add-gn.vue')
},
editFun() {
if (this.chooseData.length !== 1) {
this.$message.warning('请选择一个功能菜单后操作')
return
}
this.data = this.chooseData[0]
this.show = true
this.dialogVisible = true
this.dialogOptions = {
width: '700px',
title: '修改功能',
saveBtn: '提交'
}
this.dialogContentComponent = () =>
import('@/components/dialog/zzqx-gn/edit-gn.vue')
},
deleteFun(node, data) {
if (!this.chooseData.length) {
this.$message({
message: '请选择数据进行操作',
type: 'warning'
})
return
}
var prame = []
this.chooseData.forEach((element) => {
prame.push({ dxid: element.dxid })
})
this.$confirm('是否确定删除该数据?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
center: true
})
.then(() => {
// 删除
this.api.post(
this,
'delete_gn',
() => {
this.$message.success('删除成功')
this.dialogVisible = false // 关闭弹窗
this.reload({ dxid: this.chooseId }) // 刷新数据
},
prame
)
})
.catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
})
})
},
handleitem(val) {
this.$refs.dataGrid.load({ dxid: val.dxid })
}
}
}
</script>
<style lang="scss">
.general-wrap .rightdrig .gr-datagrid-notitle {
border-bottom: none;
}
.gr-datagrid .gr-tag ::v-deep .el-collapse {
margin: 0 22px 0 18px !important;
}
.leftshuxing {
width: 300px;
background: #fff;
margin: 3px 0 3px 5px;
}
.rightdrig {
overflow: hidden;
flex: 1;
.gr-datagrid-notitle {
height: 90%;
height: calc(100% - 45px);
background: #fff;
margin: 3px 0 3px 5px;
padding: 0 17px;
border-bottom: solid 1px #d9d9d9;
.gr-tag {
line-height: 46px;
.data-title {
background: url('~@/assets/data-title.png') no-repeat center left;
padding-left: 20px;
font-size: 14px;
}
.el-button--primary {
color: #fff;
background: #409eff;
border-color: #409eff;
margin-left: 15px;
}
.el-button--primary:hover {
background-color: rgb(193, 218, 243);
border-color: rgb(121, 184, 248);
color: #000;
}
}
}
}
</style>
目录
<template>
<ul :style="{height:heightstyle + 'px'}">
<li v-for="(val, ind) of list" :key=ind @click="handlecli(val, ind)" :class="[ind == itemindex ? 'chose':null]">
<span>{{val.mc}}</span>
</li>
</ul>
</template>
<script>
export default {
data() {
return {
heightstyle: 500,
list: null,
itemindex: 0
}
},
created() {
this.heightstyle = document.body.clientHeight - 100
this.load()
},
methods: {
handlecli(val, ind) {
this.$emit('cliitem', val)
this.$store.state.chooseId = this.list[ind].dxid
this.itemindex = ind
},
load(param) {
this.api.get(this, 'system_left_zxt', this.result, param)
},
result(data) {
this.list = data
this.$store.state.chooseId = this.list[0].dxid
this.handlecli(this.list[0], 0)
}
}
}
</script>
<style scoped lang="scss">
ul {
padding: 10px;
overflow-y: auto;
box-sizing: border-box;
margin-top: 3px;
}
li {
padding: 2px 4px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
}
li:hover {
color: #3083f2;
background-color: #f5f7fa;
}
li.chose {
color: #3083f2;
background-color: #f5f7fa;
}
</style>
表格
<template>
<div>
<search @searchSubmit="searchSubmit"></search> // 放在父页面一样
<div class="gr-tag">
<span class="data-title">功能管理</span>
<el-button type="primary" size="mini" @click="addFun">增加</el-button>
<el-button type="success" size="mini" @click="editFun">编辑</el-button>
<el-button type="info" size="mini" @click="jiny" v-if="chooseData[0] && chooseData[0].sfjy === '1'">禁用</el-button>
<el-button type="warning" size="mini" @click="kaiq" v-else>开启</el-button>
<el-button type="danger" size="mini" @click="deleteFun">删除</el-button>
</div>
<el-table @selection-change="changeCheckbox" ref="multipleTable" :data="tableData" stripe borders style="width:100%" :height="height" :tree-props="{children: 'children', hasChildren: 'hasChildren'}" row-key="dxid">
<el-table-column type="selection" width="42"/>
<el-table-column prop="mc" label="功能名称" width="230"></el-table-column>
<el-table-column prop="icon" show-overflow-tooltip label="ICON">
<template slot-scope="scope">
{{scope.row.icon || '无'}}
</template>
</el-table-column>
<el-table-column :formatter="changeLx" prop="lx" label="类型">
</el-table-column>
<el-table-column prop="sfjy" label="是否禁用">
<template slot-scope="scope" >
<span :style="{ color: scope.row.sfjy == 0 ? 'red' : '' }">
{{scope.row.sfjy == 0 ? '是' : '否'}}
</span>
</template>
</el-table-column>
<el-table-column show-overflow-tooltip prop="ms" label="描述">
<template slot-scope="scope">
{{scope.row.ms || '无'}}
</template>
</el-table-column>
<el-table-column prop="cjsj" label="创建时间" show-overflow-tooltip></el-table-column>
</el-table>
</div>
</template>
<script>
import index from './index.js'
export default index
</script>
<style lang="scss">
.el-checkbox__input.is-checked .el-checkbox__inner {
background-color: #409eff;
border-color: #409eff;
}
.el-checkbox__input.is-indeterminate .el-checkbox__inner {
background-color: #409eff;
border-color: #409eff;
}
.el-table td {
padding: 8px 0;
}
.el-tooltip__popper {
font-size: 14px;
max-width: 50%;
}
</style>
表格逻辑
import { mapState } from 'vuex'
export default {
data() {
return {
dxid: '',
currentPage: 1,
pagePize: 15,
tableData: [],
height: 500,
total: 0,
canshu: {},
currentRow: []
}
},
computed: mapState(['chooseId', 'chooseData']),
created() {
this.height = document.body.clientHeight - 110
},
methods: {
changeCheckbox(val) {
this.$store.state.chooseData = val
},
addFun() {
this.$emit('addFun')
},
editFun() {
this.$emit('editFun')
},
kaiq() {
if (this.chooseData.length !== 1) {
this.$message.warning('请选择一个功能菜单后操作')
return
}
this.chooseData[0].sfjy = '1'
this.api.post(this, 'edit_gn', () => {
this.$message.success('开启成功')
}, this.chooseData[0])
},
jiny() {
if (this.chooseData.length !== 1) {
this.$message.warning('请选择一个功能菜单后操作')
return
}
this.chooseData[0].sfjy = '0'
this.api.post(this, 'edit_gn', () => {
this.$message.success('已禁用')
}, this.chooseData[0])
},
deleteFun() {
this.$emit('deleteFun')
},
load(param) {
this.dxid = param.dxid
this.$store.state.chooseData = []
this.api.get(this, 'system_zxt_menu', this.result, param)
},
result(data) {
this.total = data.length
this.tableData = this.gettree(data)
},
gettree(data) {
var dataList = data
function fn(data, sjdxid) {
var result = []
var temp
for (var i in data) {
if (data[i].sjdxid === sjdxid) {
result.push(data[i])
temp = fn(data, data[i].dxid)
if (temp.length > 0) {
data[i].children = temp
}
}
}
return result
}
return fn(dataList, this.dxid)
},
changeLx(row) {
switch (row.lx) {
case '1':
return '平台'
case '2':
return '外链'
case '3':
return '弹窗'
case '4':
return 'iframe'
case '5':
return 'map点位绘制'
case '6':
return '服务调用'
case '7':
return 'map线、面绘制'
case '8':
return 'map面绘制'
case '9':
return 'map ICON替换'
}
},
indexMethod(index) {
return this.pageInfo.limit * (this.pageInfo.start - 1) + 1 + index
}
}
}
import组件内容(分了新增和编辑操作,看情况可合并)
新增操作(两个文件差别在逻辑不同)
<template>
<el-form :model="dataForm" label-width="110px" ref="dataForm" size="mini" :rules="rules" style="margin-right: 20px" :inline="true" label-position="right">
<el-form-item label="功能名称" prop="mc">
<el-input v-model="dataForm.mc" style="width:200px"></el-input>
</el-form-item>
<el-form-item label="访问路径" prop="fwlj">
<el-input v-model="dataForm.fwlj" style="width:200px"></el-input>
</el-form-item>
<el-form-item label="是否管理" prop="mrxs">
<el-select filterable v-model="dataForm.mrxs" placeholder="是否管理" style="width:200px">
<el-option label="是" value="1"></el-option>
<el-option label="否" value="0"></el-option>
</el-select>
</el-form-item>
<el-form-item label="icon" prop="icon">
<el-input v-model="dataForm.ICON" style="width:200px"></el-input>
</el-form-item>
<el-form-item label="描述" prop="ms">
<el-input v-model="dataForm.ms" style="width:200px"></el-input>
</el-form-item>
<el-form-item label="显示顺序" prop="xssx">
<el-input v-model="dataForm.xssx" style="width:200px"></el-input>
</el-form-item>
<el-form-item label="类型" prop="lx">
<el-select v-model="dataForm.lx" placeholder="选择类型" style="width:200px">
<el-option v-for="li in lxlist" :key="li.id" :label="li.label" :value="li.value"></el-option>
</el-select>
</el-form-item>
<!-- <el-form-item label="是否禁用" prop="sfjy">
<el-select filterable v-model="dataForm.sfjy" placeholder="是否禁用" style="width:200px">
<el-option label="是" value="1"></el-option>
<el-option label="否" value="0"></el-option>
</el-select>
</el-form-item> -->
<el-form-item label="上级对象" prop="sjdxid">
<el-select v-model="dataForm.sjdxid" filterable placeholder="选择上级对象" style="width:200px">
<el-option label="无上级菜单" value="" key=""></el-option>
<el-option :label="item.mc" :value="item.dxid" v-for="(item,index) in funList" :key="index"></el-option>
</el-select>
</el-form-item>
</el-form>
</template>
<script>
import { mapState } from 'vuex'
export default {
data() {
return {
funList: [],
dataForm: {
mc: '',
fwlj: '',
mrxs: '',
ICON: '',
sfjy: '0',
lx: '',
xssx: '',
sjc: '{datetime}',
cjsj: '{datetime}',
dxid: '{uuid}',
sjdxid: ''
},
lxlist: [
{ label: '平台', value: '1' },
{ label: '外链', value: '2' },
{ label: '弹窗', value: '3' },
{ label: 'iframe', value: '4' },
{ label: 'map点位绘制', value: '5' },
{ label: 'map服务调用', value: '6' },
{ label: 'map线、面绘制', value: '7' },
{ label: 'map面绘制', value: '8' },
{ label: 'map ICON替换', value: '9' }
],
rules: {
mrxs: [
{ required: true, message: '请选择是否默认显示', trigger: 'blur' }
],
mc: [
{ required: true, message: '请输入功能名称', trigger: 'blur' }
],
fwlj: [
{ required: true, message: '请输入访问路径', trigger: 'blur' }
],
xssx: [
{ required: true, message: '请输入显示顺序', trigger: 'blur' }
],
lx: [
{ required: true, message: '请输入类型', trigger: 'blur' }
],
sfjy: [
{ required: true, message: '请选择是否禁用', trigger: 'blur' }
]
}
}
},
computed: mapState(['chooseData', 'chooseId']),
methods: {
result(data) {
this.funList = data
},
submitForm(that) {
this.$refs.dataForm.validate(valid => {
if (!valid) {
return false
}
this.api.post(this, 'add_gn', () => {
this.$message.success('新增成功')
that.modalClose() // 关闭弹窗
that.$parent.reload({ dxid: this.chooseId })
}, this.dataForm)
})
},
resetForm() {
this.$refs.dataForm.resetFields()
}
},
created() {
for (const key in this.data) {
this.dataForm[key] = this.data[key]
}
this.api.get(this, 'gn_list', this.result)
if (this.chooseData.length) {
this.dataForm.sjdxid = this.chooseData[0].dxid
} else {
this.dataForm.sjdxid = this.chooseId
}
}
// ###编辑操作(不同于编辑的地方)
// methods: {
// submitForm(that) {
// this.$refs.dataForm.validate(valid => {
// if (!valid) {
// return false
// }
// this.api.post(this, 'edit_gn', () => {
// this.$message.success('更新成功')
// that.modalClose() // 关闭弹窗
// that.$parent.reload({ dxid: this.chooseId })
// }, this.dataForm)
// })
// }
// },
// created() {
// this.dataForm = Object.assign({ }, this.chooseData[0])
// this.api.get(this, 'gn_list', this.result)
//
}
</script>
查询条件
index.vue
<template>
<el-form :inline="true" :model="formInline" size="mini" class="gr-form-search" @submit.native.prevent>
<el-form-item label="用户名">
<el-input clearable v-model="formInline.userName" placeholder="请输入用户名"></el-input>
</el-form-item>
<el-form-item label="开始时间" prop="startTime">
<el-date-picker v-model="formInline.startTime" type="datetime" format="yyyy-MM-dd HH:mm" value-format="yyyy-MM-dd HH:mm" style="width:200px" placeholder="选择日期时间">
</el-date-picker>
</el-form-item>
<el-form-item label="结束时间" prop="endTime">
<el-date-picker v-model="formInline.endTime" type="datetime" format="yyyy-MM-dd HH:mm" value-format="yyyy-MM-dd HH:mm" style="width:200px" placeholder="选择日期时间">
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">查询</el-button>
</el-form-item>
</el-form>
</template>
<script>
import index from './index.js'
export default index
</script>
index.js
export default {
data() {
return {
formInline: {
userName: '',
startTime: '',
endTime: ''
}
}
},
mounted() {
this.onSubmit()
},
methods: {
onSubmit() {
var data = Object.assign({}, this.formInline)
this.$emit('searchSubmit', data)
}
}
}
增加查询组件,父页面相对应增加方法
load(param) {
this.api.get(this, 'getsslist', this.result, param)
},
searchSubmit(data = this.canshu) {
if (data === undefined) data = {}
data.pageSize = this.pagePize
data.pageNum = this.currentPage
this.canshu = data
this.loading = true
this.load(data)
},
searchResult(data) {
this.load(data)
}
弹窗组成文件含index.vue、index.js、directives.js
index.vue
<template>
<el-dialog :title="dialogOptions.title" :visible.sync="dialogVisible" :width="dialogOptions.width" :before-close="handleClose" v-dialogDrag>
<component ref="childFunx" :is="dialogContentComponent" :data="data" :typeSelectData="typeSelectData" :roomSelectData="roomSelectData" :day="day"></component>
<span slot="footer" class="dialog-footer" v-if="show">
<el-button @click="resetForm()">重置</el-button>
<el-button type="primary" @click="submitForm()">{{dialogOptions.saveBtn}}</el-button>
<el-button type="danger" v-if="showDel" @click="deleteDate">删除</el-button>
</span>
</el-dialog>
</template>
<script>
import grDialog from './index.js'
export default grDialog
</script>
<style lang="scss">
.el-dialog {
border-radius: 8px;
.el-dialog__header {
border-radius: 8px 8px 0 0;
background: #4991f0;
padding: 8px 15px;
.el-dialog__headerbtn {
top: 12px;
}
.el-dialog__title {
font-size: 18px;
color: #fff;
}
.el-icon-close:before {
color: #fff;
}
}
.el-dialog__body {
padding: 25px 15px 5px 15px;
}
.el-dialog__footer {
text-align: center;
padding-top: 0;
}
.el-button--primary {
color: #fff;
background-color: #409eff;
border-color: #409eff;
}
.el-button:hover {
background-color: rgb(193, 218, 243);
border-color: rgb(121, 184, 248);
color: #000;
}
}
.el-message-box {
.el-button--primary,
.el-button--primary:active {
color: #fff;
background: #409eff;
border-color: #409eff;
}
.el-button:hover {
background-color: rgb(193, 218, 243);
border-color: rgb(121, 184, 248);
color: #000;
}
}
</style>
index.js
import './directives.js'
export default {
props: {
dialogVisible: {
type: Boolean,
default: false
},
modal: {
type: Boolean,
default: true
},
dialogOptions: {
type: Object,
default: { title: '', saveBtn: '保存', width: '30%', isre: false }
},
data: { type: [Object, Array], default: () => { } },
dialogContentComponent: { type: Function },
show: { type: Boolean, default: true },
showDel: { type: Boolean, default: false },
typeSelectData: { type: Array, default: () => [] },
roomSelectData: { type: Array, default: () => [] },
day: { type: String, default: '' }
},
methods: {
resetForm() {
this.$refs.childFunx.resetForm()
},
submitForm() {
this.$refs.childFunx.submitForm(this)
},
deleteDate() {
this.$refs.childFunx.deleteDate(this)
},
modalClose() {
this.$emit('update:dialogVisible', false) // 直接修改父组件的属性
},
reLoad() {
this.$parent.reload()
},
handleClose(done) {
this.$confirm('确认关闭?')
.then(_ => {
this.modalClose()
})
.catch(_ => { })
}
}
}
directives.js(一个拖动功能)
import Vue from 'vue'
Vue.directive('dialogDrag', {
bind(el, binding, vnode, oldVnode) {
const dialogHeaderEl = el.querySelector('.el-dialog__header')
const dragDom = el.querySelector('.el-dialog')
dialogHeaderEl.style.cursor = 'move'
// 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null)
dialogHeaderEl.onmousedown = (e) => {
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - dialogHeaderEl.offsetLeft
const disY = e.clientY - dialogHeaderEl.offsetTop
// 获取到的值带px 正则匹配替换
let styL, styT
// 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
if (sty.left.includes('%')) {
styL = +document.body.clientWidth * (+sty.left.replace(/\%/g, '') / 100)
styT = +document.body.clientHeight * (+sty.top.replace(/\%/g, '') / 100)
} else {
styL = +sty.left.replace(/\px/g, '')
styT = +sty.top.replace(/\px/g, '')
}
document.onmousemove = function(e) {
// 通过事件委托,计算移动的距离
const l = e.clientX - disX
const t = e.clientY - disY
// 移动当前元素
dragDom.style.left = `${l + styL}px`
dragDom.style.top = `${t + styT}px`
// 将此时的位置传出去
// binding.value({x:e.pageX,y:e.pageY})
}
document.onmouseup = function(e) {
document.onmousemove = null
document.onmouseup = null
}
}
}
})
// v-dialogDragWidth: 弹窗宽度拖大 拖小
Vue.directive('dialogDragWidth', {
bind(el, binding, vnode, oldVnode) {
const dragDom = binding.value.$el.querySelector('.el-dialog')
el.onmousedown = (e) => {
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - el.offsetLeft
document.onmousemove = function(e) {
e.preventDefault() // 移动时禁用默认事件
// 通过事件委托,计算移动的距离
const l = e.clientX - disX
dragDom.style.width = `${l}px`
}
document.onmouseup = function(e) {
document.onmousemove = null
document.onmouseup = null
}
}
}
}
)