Commit fae68cde by qinjianhui

feat: 菜单管理

parent d227f9f7
...@@ -16,5 +16,6 @@ module.exports = { ...@@ -16,5 +16,6 @@ module.exports = {
'comma-dangle': ['error', 'always-multiline'], 'comma-dangle': ['error', 'always-multiline'],
'space-before-function-paren': 'off', 'space-before-function-paren': 'off',
indent: 'off', indent: 'off',
'multiline-ternary': 'off',
}, },
} }
...@@ -14,7 +14,9 @@ ...@@ -14,7 +14,9 @@
"js-md5": "^0.7.3", "js-md5": "^0.7.3",
"vue": "^2.6.14", "vue": "^2.6.14",
"vue-router": "^3.5.1", "vue-router": "^3.5.1",
"vuex": "^3.6.2" "vuex": "^3.6.2",
"vxe-table": "^3.5.9",
"xe-utils": "^3.5.7"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.12.16", "@babel/core": "^7.12.16",
...@@ -11694,6 +11696,15 @@ ...@@ -11694,6 +11696,15 @@
"vue": "^2.0.0" "vue": "^2.0.0"
} }
}, },
"node_modules/vxe-table": {
"version": "3.5.9",
"resolved": "https://registry.npmjs.org/vxe-table/-/vxe-table-3.5.9.tgz",
"integrity": "sha512-8idPnu377Ufwyv6/8GsAk2s9KNcF2nVdp3M8izMmrapOJ2fJRTWmaBTH//XbKqF4ELmvRPXAtkEOl6h37T7RaA==",
"peerDependencies": {
"vue": "^2.6.0",
"xe-utils": "^3.5.0"
}
},
"node_modules/watchpack": { "node_modules/watchpack": {
"version": "2.4.0", "version": "2.4.0",
"resolved": "https://registry.npmmirror.com/watchpack/-/watchpack-2.4.0.tgz", "resolved": "https://registry.npmmirror.com/watchpack/-/watchpack-2.4.0.tgz",
...@@ -12303,6 +12314,11 @@ ...@@ -12303,6 +12314,11 @@
} }
} }
}, },
"node_modules/xe-utils": {
"version": "3.5.7",
"resolved": "https://registry.npmjs.org/xe-utils/-/xe-utils-3.5.7.tgz",
"integrity": "sha512-3H+fDBKBR2wLJgyA7k9C/w1Xljx6Maml5ukV0WDY06HjYyGs2FEz6XhcwRCLIDXX4pBP3Gu0nX9DbCeuuRA2Ew=="
},
"node_modules/y18n": { "node_modules/y18n": {
"version": "5.0.8", "version": "5.0.8",
"resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz", "resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz",
...@@ -21074,6 +21090,12 @@ ...@@ -21074,6 +21090,12 @@
"integrity": "sha512-ETW44IqCgBpVomy520DT5jf8n0zoCac+sxWnn+hMe/CzaSejb/eVw2YToiXYX+Ex/AuHHia28vWTq4goAexFbw==", "integrity": "sha512-ETW44IqCgBpVomy520DT5jf8n0zoCac+sxWnn+hMe/CzaSejb/eVw2YToiXYX+Ex/AuHHia28vWTq4goAexFbw==",
"requires": {} "requires": {}
}, },
"vxe-table": {
"version": "3.5.9",
"resolved": "https://registry.npmjs.org/vxe-table/-/vxe-table-3.5.9.tgz",
"integrity": "sha512-8idPnu377Ufwyv6/8GsAk2s9KNcF2nVdp3M8izMmrapOJ2fJRTWmaBTH//XbKqF4ELmvRPXAtkEOl6h37T7RaA==",
"requires": {}
},
"watchpack": { "watchpack": {
"version": "2.4.0", "version": "2.4.0",
"resolved": "https://registry.npmmirror.com/watchpack/-/watchpack-2.4.0.tgz", "resolved": "https://registry.npmmirror.com/watchpack/-/watchpack-2.4.0.tgz",
...@@ -21515,6 +21537,11 @@ ...@@ -21515,6 +21537,11 @@
"dev": true, "dev": true,
"requires": {} "requires": {}
}, },
"xe-utils": {
"version": "3.5.7",
"resolved": "https://registry.npmjs.org/xe-utils/-/xe-utils-3.5.7.tgz",
"integrity": "sha512-3H+fDBKBR2wLJgyA7k9C/w1Xljx6Maml5ukV0WDY06HjYyGs2FEz6XhcwRCLIDXX4pBP3Gu0nX9DbCeuuRA2Ew=="
},
"y18n": { "y18n": {
"version": "5.0.8", "version": "5.0.8",
"resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz", "resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz",
......
...@@ -14,7 +14,9 @@ ...@@ -14,7 +14,9 @@
"js-md5": "^0.7.3", "js-md5": "^0.7.3",
"vue": "^2.6.14", "vue": "^2.6.14",
"vue-router": "^3.5.1", "vue-router": "^3.5.1",
"vuex": "^3.6.2" "vuex": "^3.6.2",
"vxe-table": "^3.5.9",
"xe-utils": "^3.5.7"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.12.16", "@babel/core": "^7.12.16",
......
<template> <template>
<div id="app"> <div id="app">
<router-view/> <router-view />
</div> </div>
</template> </template>
<script>
export default {
data() {
return {}
},
created() {
addEventListener('keydown', (e) => {
this.$store.dispatch('setKeyCode', e.key)
})
addEventListener('keyup', () => {
this.$store.dispatch('setKeyCode', null)
})
},
}
</script>
<style lang="less"> <style lang="less">
* { * {
......
import axios from '../axios'
export function updateSysmenu({ id, enable, type }) {
return axios.post('/sysMenu/update', null, {
params: { id, enable, type },
})
}
export function getAllMenusTree() {
return axios.get('sysMenu/getAllMenusTree')
}
export function addMenu(data) {
return axios.post('sysMenu/add', data)
}
export function updateMenu(data) {
return axios.post('sysMenu/update', data)
}
export function deleteMenu(id) {
return axios.post(`sysMenu/delete/${id}`)
}
<script>
export default {
name: 'myLayout',
inheritAttrs: false,
props: {
isleftshow: {
default: true,
type: Boolean,
},
},
data() {
return {
isLeft: true,
}
},
methods: {
leftChange() {
this.isLeft = !this.isLeft
},
},
render() {
const {
$scopedSlots,
$attrs,
isLeft,
isleftshow,
$vnode,
} = this
const leftStyle = $attrs?.leftStyle || {}
let { width, ...attrs } = leftStyle
if (!width) width = '200px'
return (
<div class="page_main">
{$scopedSlots.header && (
<div class="page_header">
{$scopedSlots.header()}
</div>
)}
<div
class="layout_wrap"
style={$vnode.data.staticStyle}
>
{$scopedSlots.page_left && (
<div
class="page_left"
style={{
...attrs,
width: isLeft ? width : '1px',
}}
>
{$scopedSlots.page_left()}
</div>
)}
{isleftshow && (
<div class="separation">
<span
class="left_toggle"
title={isLeft ? '点击收起' : '点击展开'}
onClick={this.leftChange}
>
<i
class={
isLeft
? 'el-icon-caret-left'
: 'el-icon-caret-right'
}
></i>
</span>
</div>
)}
{$scopedSlots.page_right && (
<div
class="page_right"
style={$attrs?.rightStyle || {}}
>
{$scopedSlots.page_right()}
</div>
)}
{$scopedSlots.default && $scopedSlots.default()}
</div>
</div>
)
},
}
</script>
<style scoped>
.page_main {
height: calc(100vh - 86px);
box-sizing: border-box;
display: flex;
flex-direction: column;
margin: 0;
overflow: hidden;
position: relative;
}
.page_main .layout_wrap {
height: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
position: relative;
}
.page_main:not(.mobile) {
margin-right: 40px;
}
/* .page_main.home .tool_warper {
display: none;
} */
.page_main.row .layout_wrap {
flex-direction: row;
}
.page_main.wrap .layout_wrap {
background: #fff;
box-sizing: border-box;
border-radius: 10px;
padding-top: 10px;
}
.page_main.wrap .layout_wrap >>> form:nth-of-type(1) {
margin-left: 10px;
}
.page_main.mobile {
height: calc(100vh - 56px);
}
.page_header {
background: #fff;
padding-top: 10px;
margin-bottom: 10px;
}
.page_left {
position: relative;
display: flex;
flex-direction: column;
width: 200px;
height: 100%;
background: var(--background-color);
box-sizing: border-box;
border-radius: 5px 5px 0 0;
overflow: auto;
}
.separation {
display: none;
position: relative;
width: 1px;
}
.row .separation {
display: block;
}
.separation .left_toggle {
position: absolute;
right: -16px;
width: 17px;
height: 24px;
background: #dedede;
z-index: 1000;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
.separation .left_toggle::before {
position: absolute;
width: 0px;
height: 0px;
content: '';
top: 10px;
left: -12px;
pointer-events: none;
transform: rotate(45deg);
border-width: 12px;
border-style: solid;
border-color: rgba(0, 0, 0, 0) #dedede rgba(0, 0, 0, 0)
rgba(0, 0, 0, 0);
border-radius: 5px;
}
.separation .left_toggle::after {
position: absolute;
width: 0px;
height: 0px;
top: -10px;
left: -12px;
pointer-events: none;
content: '';
transform: rotate(-45deg);
border-width: 12px;
border-style: solid;
border-color: rgba(0, 0, 0, 0) #dedede rgba(0, 0, 0, 0)
rgba(0, 0, 0, 0);
border-radius: 5px;
}
.separation .left_toggle i {
display: block;
margin-top: 3px;
pointer-events: none;
}
.separation:hover .left_toggle {
display: block;
}
.page_right {
flex: 1;
display: flex;
flex-direction: column;
margin-left: 10px;
box-sizing: border-box;
overflow: hidden;
}
.page_main:not(.drag) .page_right {
background: var(--background-color);
border-radius: 5px 5px 0 0;
padding-top: 10px;
box-sizing: border-box;
}
.page_main .page_right >>> form:nth-of-type(1),
.page_main .page_left >>> form,
.page_main.drag >>> form {
padding-left: 10px;
}
/* .page_right >>> .top {
padding-top: 0;
} */
.page_main.drag .page_right {
/* padding-top: 10px; */
background: transparent;
}
</style>
<script>
import { mapState } from 'vuex'
const globalIndex = Math.random()
function getKey() {
return Math.random().toString().substr(3, 10)
}
export default {
name: 'my-table',
components: {},
props: {
rowKey: {
type: String,
default: '_id',
},
tableColumns: {
type: Array,
default: () => [],
},
sourceData: {
type: Array,
default: () => [],
},
selectMore: {
type: Boolean,
default: false,
},
// 排序
serverSort: {
type: Boolean,
default: false,
},
treeConfig: {
type: Object,
default: () => {},
},
expandConfig: {
type: Object,
default: () => {},
},
stripe: {
type: Boolean,
default: false,
},
showHeader: {
type: Boolean,
default: true,
},
isFooter: {
type: Boolean,
default: false,
},
more: {
type: Boolean,
default: false,
},
pageSize: {
type: Number,
default: 100,
},
serialNumber: {
type: Boolean,
default: true,
},
selection: {
type: Boolean,
default: false,
},
radio: {
type: Boolean,
default: false,
},
footerMethod: {
type: Function,
default: () => {},
},
cellClick: {
type: Function,
default: () => {},
},
footerSpanMethod: {
type: Function,
default: () => {},
},
rowClassName: {
type: Function,
default: () => {},
},
highIds: {
// 高亮显示行
type: Array,
default: () => [],
},
highFirst: {
type: Boolean,
default: false,
},
spanMethod: {
type: Function,
default: () => {},
},
checkboxConfig: {
type: Object,
default: () => {},
},
customRightMenu: {
type: Object,
default: () => ({
code: '',
name: '',
prefixIcon: '',
disabled: false,
}),
},
virtualScroll: {
type: Boolean,
default: true,
},
},
computed: {
...mapState({
keyCode: 'keyCode',
// oldSelection: (state) => state.Order.oldSelection,
}),
tableMenu() {
const obj = {
header: {
options: [
[
{
code: 'hideColumn',
name: '隐藏列',
disabled: false,
},
{
code: 'showAllColumn',
name: '取消所有隐藏列',
disabled: false,
},
],
],
},
body: {
options: [
[
{
code: 'checkAll',
name: '全部选择',
disabled: false,
},
{
code: 'cancelSelection',
name: '取消选择',
disabled: true,
},
{
code: 'copy',
name: '复制',
prefixIcon: 'fa fa-copy',
disabled: false,
},
],
],
},
// visibleMethod: this.visibleMethod
}
if (this.$props.customRightMenu?.name) {
const { code, name, prefixIcon, disabled } =
this.$props.customRightMenu
obj.body.options[0].push({
code,
name,
prefixIcon,
disabled,
})
}
return obj
},
},
watch: {
sourceData(data) {
this.$refs.vxetable.clearCheckboxRow()
setTimeout(() => {
if (data.length > 0 && this.highFirst) {
if (this.selection) {
this.$refs.vxetable.setCheckboxRow(
[data[0]],
true,
)
} else if (this.radio) {
this.$refs.vxetable.setRadioRow(
this.sourceData[0],
)
this.$refs.vxetable.setCurrentRow(data[0])
} else {
this.$refs.vxetable.setCurrentRow(data[0])
}
this.$emit('selectionChange', [data[0]])
this.$emit('currentChange', { row: data[0] })
} else {
this.$emit('selectionChange', [])
this.$emit('currentChange', { row: null })
}
}, 100)
},
tableColumns(newdata, olddata) {
console.log('tableColumns')
if (
newdata &&
olddata &&
olddata.length > 0 &&
newdata !== olddata
) {
this.tableKey = getKey()
setTimeout(() => {
if (
this.sourceData.length > 0 &&
this.highFirst
) {
if (this.selection) {
this.$refs.vxetable.setCheckboxRow(
[this.sourceData[0]],
true,
)
} else if (this.radio) {
this.$refs.vxetable.setRadioRow(
this.sourceData[0],
)
this.$refs.vxetable.setCurrentRow(
this.sourceData[0],
)
} else {
this.$refs.vxetable.setCurrentRow(
this.sourceData[0],
)
}
this.$emit('selectionChange', [
this.sourceData[0],
])
// this.$emit('currentChange', { row: this.sourceData[0] })
}
}, 200)
}
},
// oldSelection(list) {
// setTimeout(() => {
// this.$refs.vxetable.clearCheckboxRow()
// this.$refs.vxetable.setCheckboxRow(list, true)
// this.$emit('selectionChange', list)
// this.$emit('currentChange', { row: null })
// }, 200)
// },
selection() {
this.tableKey = getKey()
},
},
data() {
return {
loading: false,
notSelected: false,
tableData: [],
selections: [],
startIndex: null,
tableKey: getKey(),
}
},
methods: {
reloadData() {
this.$refs.vxetable.reloadData(this.sourceData)
},
toggleRowExpand(obj) {
this.$emit('toggleRowExpand', obj)
},
syncResize() {
if (this.selectMore && this.notSelected) {
return '1'
} else {
return '2'
}
},
setCheckboxRow(rows, checked) {
this.$nextTick(() => {
this.$refs.vxetable.clearCheckboxRow()
this.$refs.vxetable.setCheckboxRow(rows, checked)
this.$emit('selectionChange', rows)
})
},
// 行点击
currentChange(options) {
const { row, $rowIndex } = options
if (this.keyCode) {
if (this.keyCode === 'Shift') {
this.$refs.vxetable.clearCheckboxRow()
let m, l
if ($rowIndex > this.startIndex) {
m = this.startIndex
l = $rowIndex
} else {
m = $rowIndex
l = this.startIndex
}
const arr = []
for (let i = m; i <= l; i++) {
arr.push(this.sourceData[i])
}
this.$refs.vxetable.setCheckboxRow(arr, true)
this.$emit('selectionChange', arr)
} else if (this.keyCode === 'Control') {
this.$refs.vxetable.setCheckboxRow([row], true)
const arr1 =
this.$refs.vxetable.getCheckboxRecords()
this.$emit('selectionChange', arr1)
} else {
this.startIndex = $rowIndex
this.$emit('currentChange', options)
try {
if (this.selection) {
this.$refs.vxetable.clearCheckboxRow()
this.$refs.vxetable.setCheckboxRow(
[row],
true,
)
this.$emit('selectionChange', [options.row])
}
if (this.radio) {
this.$refs.vxetable.clearRadioRow()
this.$refs.vxetable.setRadioRow(row)
this.$emit('selectionChange', [options.row])
}
} catch (error) {
this.$alert(error, '错误提示')
}
}
} else {
this.startIndex = $rowIndex
this.$emit('currentChange', options)
try {
if (this.selection) {
this.$refs.vxetable.clearCheckboxRow()
this.$refs.vxetable.setCheckboxRow([row], true)
this.$emit('selectionChange', [options.row])
}
if (this.radio) {
this.$refs.vxetable.clearRadioRow()
this.$refs.vxetable.setRadioRow(row)
this.$emit('selectionChange', [options.row])
}
} catch (error) {
this.$alert(error, '错误提示')
}
}
},
cellClassName({ row }) {
const item = this.highIds.find(
(item) => item === row.id,
)
if (item) {
return 'green'
}
return ''
},
// 单选
radioChange(options) {
this.$emit('currentChange', options)
this.$emit('selectionChange', [options.row])
},
// 多选
checkboxChange({ records }) {
if (records > 0) {
this.tableMenu.body.options[0][1].disabled = false
} else {
this.tableMenu.body.options[0][1].disabled = true
}
this.$emit('selectionChange', records)
},
// 全选
checkboxAll({ records, checked }) {
this.notSelected = checked
if (records > 0) {
this.tableMenu.body.options[0][1].disabled = false
} else {
this.tableMenu.body.options[0][1].disabled = true
}
if (checked) {
this.$emit('selectAll', false)
}
this.$emit('selectionChange', records)
},
// 复制
copyText(text) {
const input = document.createElement('input')
// input.style.display = 'none'
document.body.appendChild(input)
input.value = text
input.select()
if (document.execCommand('copy')) {
document.execCommand('copy')
}
document.body.removeChild(input)
},
selectAll(e) {
e && e.stopPropagation()
this.$emit('selectAll', true)
},
// 右键菜单
menuClick({ menu, row, column, $event }) {
switch (menu.code) {
case 'copy': // 复制
if (row && column) {
let text = $event.target.innerHTML
if (/<.+?>/g.test(text)) {
text = row[column.property]
}
if (!text) {
text = 'null'
}
this.copyText(text)
}
break
case 'checkAll': // 全选
this.$refs.vxetable.setAllCheckboxRow(true)
this.tableMenu.body.options[0][0].disabled = true
this.tableMenu.body.options[0][1].disabled = false
// this.$set(this.tableMenu.body.options[0][0],'disabled',true)
break
case 'cancelSelection': // 取消全选
this.$refs.vxetable.setAllCheckboxRow(false)
this.tableMenu.body.options[0][0].disabled = false
this.tableMenu.body.options[0][1].disabled = true
// this.$set(this.tableMenu.body.options[0][0],'disabled',true)
break
case 'hideColumn': // 隐藏列
if (!column.property) {
return this.$message.warning(
'当前列不支持此操作',
)
}
this.$emit('columnChange', {
column: column.property,
key: 'show',
value: false,
})
// this.$set(this.tableMenu.body.options[0][0],'disabled',true)
break
case 'showAllColumn': // 显示所有列
this.$emit('columnChange', {
column: 'all',
key: 'show',
value: true,
})
// this.$set(this.tableMenu.body.options[0][0],'disabled',true)
break
}
if (this.$props.customRightMenu?.func) {
if (
this.$props.customRightMenu.code === menu.code
) {
this.$props.customRightMenu.func(
row,
column,
$event,
)
}
}
},
// 排序
sortChange({ property, order }) {
this.$emit('sortChange', { property, order })
},
// 手动设置排序
setSort({ order, prop }) {
this.$refs.vxetable.sort(prop, order)
},
showToggle() {
this.loading = !this.loading
},
getIndex(index) {
return globalIndex + index
},
// 列宽拖动
resizableChange({ column }) {
this.$emit('columnChange', {
column: column.property,
key: 'width',
value: column.resizeWidth,
})
},
renderColumn(item, index, classname) {
const slots = {
default: ({ row, $rowIndex }) => {
if (item.type) return null
if (item.render) {
return item.render(row, item.key, $rowIndex)
}
return row[item.key]
},
}
if (item.content) {
slots.content = ({ row }) =>
item.content ? item.content(row, item.key) : null
}
if (item.title) {
slots.header = () =>
item.title ? item.title(item.label) : item.label
}
return (
<vxe-table-column
type={item.type}
title={item.label}
field={item.key}
tree-node={item.treeNode}
fixed={item.fixed}
header-class-name={classname}
key={this.getIndex(index)}
width={item.width}
min-width={item.minWidth}
header-align="center"
sortable={item.sortable}
align={item.align || 'center'}
scopedSlots={slots}
></vxe-table-column>
)
},
},
render() {
const isShow = this.tableColumns.length > 0
const checkboxconfig = {
reserve: true,
highlight: true,
}
if (this.checkboxConfig) {
for (const key in this.checkboxConfig) {
checkboxconfig[key] = this.checkboxConfig[key]
}
}
return (
<vxe-table
ref="vxetable"
border
size="mini"
class="my-table"
resizable
sort-config={{
trigger: 'cell',
remote: this.serverSort,
orders: ['desc', 'asc', 'null'],
}}
menu-config={this.tableMenu}
checkbox-config={checkboxconfig}
data={this.sourceData}
auto-resize
sync-resize={this.syncResize()}
highlight-current-row
highlight-hover-row
show-header={this.showHeader}
onCell-click={this.cellClick}
show-header-overflow
show-overflow
height="100%"
scroll-x={{ gt: 30 }}
scroll-y={{ gt: 30, enabled: this.virtualScroll }}
row-id={this.rowKey}
empty-text="暂无数据"
loading={this.loading}
cell-class-name={this.cellClassName}
row-class-name={this.rowClassName}
onCurrent-change={this.currentChange}
onCheckbox-change={this.checkboxChange}
onCheckbox-all={this.checkboxAll}
onResizable-change={this.resizableChange}
onMenu-click={this.menuClick}
onToggle-row-expand={this.toggleRowExpand}
expand-config={this.expandConfig}
span-method={this.spanMethod}
onRadio-change={this.radioChange}
onSort-change={this.sortChange}
show-footer={this.isFooter}
footer-method={this.footerMethod}
footer-span-method={this.footerSpanMethod}
tree-config={this.treeConfig}
stripe={this.stripe}
{...{ props: this.$attrs, on: this.$listeners }}
key={this.tableKey}
>
{isShow && this.selection && (
<vxe-table-column
fixed="left"
field="selection"
type="checkbox"
align="center"
width={
this.selectMore && this.notSelected ? 120 : 40
}
// width="120"
scopedSlots={{
title: ({ checked }) =>
this.selectMore && checked ? (
<el-button
slot="header"
type="text"
size="default"
onClick={this.selectAll}
style={{
color: this.more ? 'red' : '#4168FF',
}}
>
{this.more
? `${this.pageSize}+ selected`
: `select ${this.pageSize}+`}
</el-button>
) : null,
}}
></vxe-table-column>
)}
{isShow && this.radio && (
<vxe-table-column
fixed="left"
type="radio"
title=""
field="radio"
align="center"
width="40"
></vxe-table-column>
)}
{isShow && this.serialNumber && (
<vxe-table-column
type="seq"
title="序号"
field="num"
scopedSlots={{
default: this.$scopedSlots.serialNumberRender,
}}
align="center"
width="60"
></vxe-table-column>
)}
{this.tableColumns.map((item, index) => {
if (item.show === false) {
return null
}
if (item.subTitle) {
return (
<vxe-table-colgroup
header-align="center"
header-class-name="tablecolgroup"
title={item.label}
>
{item.subTitle.map((subitem, index1) => {
return this.renderColumn(
subitem,
index1,
'tablecolgroup',
)
})}
</vxe-table-colgroup>
)
} else {
return this.renderColumn(item, index)
}
})}
</vxe-table>
)
},
}
</script>
<style scoped>
.scroller {
height: 100%;
}
.my-table {
vertical-align: middle;
}
/* .my-table >>> .vxe-body--column,
.my-table >>> .vxe-header--column.col--ellipsis,
.my-table >>> .vxe-body--column.col--ellipsis,
.my-table >>> .vxe-footer--column.col--ellipsis {
height: 30px;
} */
.my-table >>> .vxe-checkbox--label {
padding-left: 0;
}
.my-table >>> .vxe-header--column.tablecolgroup,
.my-table
>>> .vxe-header--column.col--ellipsis.tablecolgroup {
height: 22px !important;
}
.my-table >>> .vxe-cell {
/* max-height: 30px !important; */
padding-left: 5px;
padding-right: 5px;
}
.my-table >>> .green {
background: green;
color: #fff;
}
</style>
...@@ -16,6 +16,8 @@ import { ...@@ -16,6 +16,8 @@ import {
Switch, Switch,
Select, Select,
Option, Option,
Cascader,
Radio,
} from 'element-ui' } from 'element-ui'
const components = [ const components = [
...@@ -31,6 +33,8 @@ const components = [ ...@@ -31,6 +33,8 @@ const components = [
Switch, Switch,
Select, Select,
Option, Option,
Cascader,
Radio,
] ]
export default { export default {
......
import 'xe-utils'
import 'vxe-table/lib/style.css'
import {
Table,
Column,
Header,
Footer,
Filter,
Edit,
Menu,
Export,
Keyboard,
Validator,
Icon,
Grid,
Toolbar,
Pager,
Checkbox,
Radio,
Input,
Button,
Modal,
Tooltip,
Form,
Select,
Switch,
List,
Colgroup,
} from 'vxe-table'
const vxes = [
Column,
Header,
Footer,
Filter,
Edit,
Menu,
Export,
Keyboard,
Validator,
Icon,
Grid,
Toolbar,
Pager,
Checkbox,
Radio,
Input,
Button,
Modal,
Tooltip,
Form,
Select,
Switch,
List,
Colgroup,
Table,
]
export default {
install(Vue) {
vxes.forEach((v) => {
Vue.use(v)
})
},
}
// 给 vue 实例挂载内部对象,例如:
// Vue.prototype.$XModal = VXETable.modal
// Vue.prototype.$XPrint = VXETable.print
// Vue.prototype.$XSaveFile = VXETable.saveFile
// Vue.prototype.$XReadFile = VXETable.readFile
...@@ -3,11 +3,13 @@ import App from './App.vue' ...@@ -3,11 +3,13 @@ import App from './App.vue'
import router from './router' import router from './router'
import store from './store' import store from './store'
import element from '@/common/components/element-ui.js' import element from '@/common/components/element-ui.js'
import vxeTable from '@/common/components/vxeTable.js'
import './common/style/index.scss' import './common/style/index.scss'
Vue.config.productionTip = false Vue.config.productionTip = false
Vue.use(element) Vue.use(element)
Vue.use(vxeTable)
new Vue({ new Vue({
router, router,
......
...@@ -3,6 +3,7 @@ import VueRouter from 'vue-router' ...@@ -3,6 +3,7 @@ import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue' import HomeView from '../views/HomeView.vue'
import SaasManage from '@/views/saasManage/indexPage.vue' import SaasManage from '@/views/saasManage/indexPage.vue'
import LoginPage from '@/views/LoginPage.vue' import LoginPage from '@/views/LoginPage.vue'
import menu from '@/views/menu'
Vue.use(VueRouter) Vue.use(VueRouter)
...@@ -22,6 +23,11 @@ const routes = [ ...@@ -22,6 +23,11 @@ const routes = [
name: 'saasManage', name: 'saasManage',
component: SaasManage, component: SaasManage,
}, },
{
path: '/saas/menu',
component: menu,
name: 'saasMenu',
},
] ]
const router = new VueRouter({ const router = new VueRouter({
......
...@@ -4,9 +4,19 @@ import Vuex from 'vuex' ...@@ -4,9 +4,19 @@ import Vuex from 'vuex'
Vue.use(Vuex) Vue.use(Vuex)
export default new Vuex.Store({ export default new Vuex.Store({
state: {}, state: {
keyCode: null,
},
getters: {}, getters: {},
mutations: {}, mutations: {
actions: {}, setKeyCode(state, msg) {
state.keyCode = msg
},
},
actions: {
setKeyCode({ commit }, msg) {
commit('setKeyCode', msg)
},
},
modules: {}, modules: {},
}) })
<template> <template>
<layout class="wrap"> <div class="system-menu">
<el-form <div class="header">
size="mini" <el-form
:inline="true" size="mini"
label-width="80px" :inline="true"
style="margin-left: 10px" label-width="80px"
> >
<el-form-item label> <el-form-item label>
<el-button type="primary" @click="showDialog({ id: 0 }, 2)"> <el-button
新增 type="primary"
</el-button> @click="showDialog({ id: 0 }, 2)"
</el-form-item> >
</el-form> 新增
<div class="table_wrap"> </el-button>
<my-table </el-form-item>
</el-form>
</div>
<div class="table-wrap" v-loading="loading">
<table-view
:tableColumns="tableColumns" :tableColumns="tableColumns"
rowKey="id" rowKey="id"
:serialNumber="false" :serialNumber="false"
:treeConfig="{ children: 'children', reserve: true }" :treeConfig="{
children: 'children',
reserve: true,
}"
:sourceData="sourceData" :sourceData="sourceData"
></my-table> ></table-view>
</div> </div>
<el-dialog <el-dialog
...@@ -38,7 +46,10 @@ ...@@ -38,7 +46,10 @@
:model="editForm" :model="editForm"
> >
<el-form-item label="菜单名称" prop="name" required> <el-form-item label="菜单名称" prop="name" required>
<el-input style="width: 164px" v-model="editForm.name"></el-input> <el-input
style="width: 164px"
v-model="editForm.name"
></el-input>
</el-form-item> </el-form-item>
<el-form-item label="父级菜单"> <el-form-item label="父级菜单">
<el-cascader <el-cascader
...@@ -51,7 +62,7 @@ ...@@ -51,7 +62,7 @@
checkStrictly: true, checkStrictly: true,
label: 'name', label: 'name',
value: 'id', value: 'id',
emitPath: false emitPath: false,
}" }"
clearable clearable
></el-cascader> ></el-cascader>
...@@ -78,15 +89,29 @@ ...@@ -78,15 +89,29 @@
></el-input> ></el-input>
</el-form-item> </el-form-item>
<el-form-item label="路径地址"> <el-form-item label="路径地址">
<el-input style="width: 164px" v-model="editForm.route"></el-input> <el-input
style="width: 164px"
v-model="editForm.route"
></el-input>
</el-form-item> </el-form-item>
<el-form-item label="接口路径"> <el-form-item label="接口路径">
<el-input style="width: 164px" v-model="editForm.url"></el-input> <el-input
style="width: 164px"
v-model="editForm.url"
></el-input>
</el-form-item> </el-form-item>
<el-form-item label="启用状态"> <el-form-item label="启用状态">
<div style="width: 164px; display: inline-block"> <div style="width: 164px; display: inline-block">
<el-radio v-model="editForm.enable" :label="true">启用</el-radio> <el-radio
<el-radio v-model="editForm.enable" :label="false">禁用</el-radio> v-model="editForm.enable"
:label="true"
>启用</el-radio
>
<el-radio
v-model="editForm.enable"
:label="false"
>禁用</el-radio
>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label=" 排序"> <el-form-item label=" 排序">
...@@ -97,29 +122,52 @@ ...@@ -97,29 +122,52 @@
></el-input> ></el-input>
</el-form-item> </el-form-item>
<el-form-item label="标题"> <el-form-item label="标题">
<el-input style="width: 164px" v-model="editForm.title"></el-input> <el-input
style="width: 164px"
v-model="editForm.title"
></el-input>
</el-form-item> </el-form-item>
<el-form-item label="备注"> <el-form-item label="备注">
<el-input style="width: 164px" v-model="editForm.describe"></el-input> <el-input
style="width: 164px"
v-model="editForm.describe"
></el-input>
</el-form-item> </el-form-item>
</el-form> </el-form>
<div slot="footer"> <div slot="footer">
<el-button size="mini" @click="clone">取 消</el-button> <el-button size="mini" @click="clone"
<el-button size="mini" type="primary" @click="submit">保 存</el-button> >取 消</el-button
>
<el-button
size="mini"
type="primary"
@click="submit"
>保 存</el-button
>
</div> </div>
</el-dialog> </el-dialog>
</layout> </div>
</template> </template>
<script> <script>
import { get, post } from '../utils/axios' import tableView from '@/common/components/base/tableView.vue'
import MyTable from '../components/base/table.vue' // import myLayout from '@/common/components/base/myLayout.vue'
import {
updateSysmenu,
getAllMenusTree,
updateMenu,
addMenu,
deleteMenu,
} from '../common/api/sys'
export default { export default {
name: 'menu_management', name: 'menu_management',
components: { components: {
MyTable tableView,
// myLayout,
}, },
data() { data() {
return { return {
loading: false,
sourceData: [], sourceData: [],
dialogVisible: false, dialogVisible: false,
editForm: { editForm: {
...@@ -130,12 +178,18 @@ export default { ...@@ -130,12 +178,18 @@ export default {
url: '', url: '',
title: '', title: '',
describe: '', describe: '',
enable: true enable: true,
}, },
rules: { rules: {
type: [{ required: true, message: ' ', trigger: 'change' }] type: [
{
required: true,
message: ' ',
trigger: 'change',
},
],
}, },
isEdit: false isEdit: false,
} }
}, },
computed: { computed: {
...@@ -146,14 +200,15 @@ export default { ...@@ -146,14 +200,15 @@ export default {
key: 'name', key: 'name',
width: '', width: '',
align: 'left', align: 'left',
treeNode: true treeNode: true,
}, },
{ {
label: '类型', label: '类型',
key: 'type', key: 'type',
width: '', width: '',
render: (item) => (item.type === 1 ? '按钮' : '菜单') render: (item) =>
item.type === 1 ? '按钮' : '菜单',
}, },
{ label: '路径名称', key: 'path', width: '' }, { label: '路径名称', key: 'path', width: '' },
{ label: '路径地址', key: 'route', width: '' }, { label: '路径地址', key: 'route', width: '' },
...@@ -169,7 +224,7 @@ export default { ...@@ -169,7 +224,7 @@ export default {
onChange={(v) => this.enableChange(item, v)} onChange={(v) => this.enableChange(item, v)}
label="" label=""
></el-checkbox> ></el-checkbox>
) ),
}, },
{ label: '标题', key: 'title', width: '' }, { label: '标题', key: 'title', width: '' },
{ label: '备注', key: 'describe', width: '' }, { label: '备注', key: 'describe', width: '' },
...@@ -204,12 +259,14 @@ export default { ...@@ -204,12 +259,14 @@ export default {
</el-button> </el-button>
)} )}
</div> </div>
) ),
} },
] ]
}, },
showMenu() { showMenu() {
const data = JSON.parse(JSON.stringify(this.sourceData)) const data = JSON.parse(
JSON.stringify(this.sourceData),
)
const arr = [] const arr = []
for (const iterator of data) { for (const iterator of data) {
const children = [] const children = []
...@@ -235,46 +292,44 @@ export default { ...@@ -235,46 +292,44 @@ export default {
sortNo: 0, sortNo: 0,
title: '', title: '',
type: 0, type: 0,
url: '' url: '',
} },
] ]
} },
}, },
mounted() { mounted() {
this.getlist() // this.getlist()
}, },
methods: { methods: {
enableChange(item, v) { async enableChange(item, v) {
post('sysMenu/update', { try {
id: item.id, const res = await updateSysmenu({
enable: v, id: item.id,
type: item.type enable: v,
}) type: item.type,
.then((res) => {
if (res.code === 200) {
this.$message.success(res.message)
item.enable = v
}
}) })
.catch(() => {}) if (res.code === 200) {
this.$message.success(res.message)
item.enable = v
}
} catch (e) {
console.error(e)
}
}, },
// loadFunc(row, treeNode, resolve) { async getlist(id, cb) {
// console.log(row); this.loading = true
try {
// this.getlist(row.id, data => resolve(data)); const res = await getAllMenusTree()
// }, if (res.code === 200) {
getlist(id, cb) { if (cb) {
get('sysMenu/getAllMenusTree') cb(res.data)
.then((res) => { } else {
if (res.code === 200) { this.sourceData = res.data
if (cb) {
cb(res.data)
} else {
this.sourceData = res.data
}
} }
}) }
.catch(() => {}) } catch (e) {
console.error(e)
}
}, },
resetForm() { resetForm() {
for (const key in this.editForm) { for (const key in this.editForm) {
...@@ -291,43 +346,51 @@ export default { ...@@ -291,43 +346,51 @@ export default {
this.editForm = { ...item, enable: true } this.editForm = { ...item, enable: true }
} }
this.$nextTick(() => { this.$nextTick(() => {
this.$refs.editForm && this.$refs.editForm.clearValidate() this.$refs.editForm &&
this.$refs.editForm.clearValidate()
}) })
this.dialogVisible = true this.dialogVisible = true
}, },
submit() { async submit() {
this.$refs.editForm.validate((v) => { try {
if (v) { if (!(await this.$refs.editForm.validate())) return
const url = this.isEdit ? 'sysMenu/update' : 'sysMenu/add' } catch {
delete this.editForm.children return
post(url, { }
...this.editForm const api = this.isEdit ? updateMenu : addMenu
}) delete this.editForm.children
.then((res) => { try {
if (res.code === 200) { const res = await api({ ...this.editForm })
this.$message.success(res.message) if (res.code === 200) {
this.getlist() this.$message.success(res.message)
} this.getlist()
})
.catch(() => {})
this.resetForm()
this.dialogVisible = false
} }
}) } catch (e) {
console.error(e)
} finally {
this.resetForm()
this.dialogVisible = false
}
}, },
remove(item) { async remove(item) {
this.$confirm('确认删除?', '提示', { try {
confirmButtonText: '确定', await this.$confirm('确认删除?', '提示', {
cancelButtonText: '取消', confirmButtonText: '确定',
type: 'warning' cancelButtonText: '取消',
}).then(() => { type: 'warning',
post('sysMenu/delete/' + item.id).then((res) => {
if (res.code === 200) {
this.$message.success(res.message)
this.getlist()
}
}) })
}) } catch {
return
}
try {
const res = await deleteMenu(item.id)
if (res.code === 200) {
this.$message.success(res.message)
this.getlist()
}
} catch (e) {
console.error(e)
}
}, },
clone() { clone() {
this.resetForm() this.resetForm()
...@@ -336,8 +399,20 @@ export default { ...@@ -336,8 +399,20 @@ export default {
beforeClose(clone) { beforeClose(clone) {
this.resetForm() this.resetForm()
clone() clone()
} },
} },
} }
</script> </script>
<style scoped></style> <style lang="scss" scoped>
.system-menu {
height: 100%;
display: flex;
flex-direction: column;
padding: 0 20px;
padding-top: 10px;
}
.table-wrap {
flex: 1;
}
</style>
...@@ -247,6 +247,7 @@ ...@@ -247,6 +247,7 @@
style="width: 200px" style="width: 200px"
v-model.trim="editForm.domain" v-model.trim="editForm.domain"
size="small" size="small"
:disabled="!!editId"
clearable clearable
@change="onChange" @change="onChange"
placeholder="请输入域名" placeholder="请输入域名"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment