Commit fae68cde by qinjianhui

feat: 菜单管理

parent d227f9f7
......@@ -16,5 +16,6 @@ module.exports = {
'comma-dangle': ['error', 'always-multiline'],
'space-before-function-paren': 'off',
indent: 'off',
'multiline-ternary': 'off',
},
}
......@@ -14,7 +14,9 @@
"js-md5": "^0.7.3",
"vue": "^2.6.14",
"vue-router": "^3.5.1",
"vuex": "^3.6.2"
"vuex": "^3.6.2",
"vxe-table": "^3.5.9",
"xe-utils": "^3.5.7"
},
"devDependencies": {
"@babel/core": "^7.12.16",
......@@ -11694,6 +11696,15 @@
"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": {
"version": "2.4.0",
"resolved": "https://registry.npmmirror.com/watchpack/-/watchpack-2.4.0.tgz",
......@@ -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": {
"version": "5.0.8",
"resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz",
......@@ -21074,6 +21090,12 @@
"integrity": "sha512-ETW44IqCgBpVomy520DT5jf8n0zoCac+sxWnn+hMe/CzaSejb/eVw2YToiXYX+Ex/AuHHia28vWTq4goAexFbw==",
"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": {
"version": "2.4.0",
"resolved": "https://registry.npmmirror.com/watchpack/-/watchpack-2.4.0.tgz",
......@@ -21515,6 +21537,11 @@
"dev": true,
"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": {
"version": "5.0.8",
"resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz",
......
......@@ -14,7 +14,9 @@
"js-md5": "^0.7.3",
"vue": "^2.6.14",
"vue-router": "^3.5.1",
"vuex": "^3.6.2"
"vuex": "^3.6.2",
"vxe-table": "^3.5.9",
"xe-utils": "^3.5.7"
},
"devDependencies": {
"@babel/core": "^7.12.16",
......
<template>
<div id="app">
<router-view/>
<router-view />
</div>
</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">
* {
......
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 {
Switch,
Select,
Option,
Cascader,
Radio,
} from 'element-ui'
const components = [
......@@ -31,6 +33,8 @@ const components = [
Switch,
Select,
Option,
Cascader,
Radio,
]
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'
import router from './router'
import store from './store'
import element from '@/common/components/element-ui.js'
import vxeTable from '@/common/components/vxeTable.js'
import './common/style/index.scss'
Vue.config.productionTip = false
Vue.use(element)
Vue.use(vxeTable)
new Vue({
router,
......
......@@ -3,6 +3,7 @@ import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue'
import SaasManage from '@/views/saasManage/indexPage.vue'
import LoginPage from '@/views/LoginPage.vue'
import menu from '@/views/menu'
Vue.use(VueRouter)
......@@ -22,6 +23,11 @@ const routes = [
name: 'saasManage',
component: SaasManage,
},
{
path: '/saas/menu',
component: menu,
name: 'saasMenu',
},
]
const router = new VueRouter({
......
......@@ -4,9 +4,19 @@ import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {},
state: {
keyCode: null,
},
getters: {},
mutations: {},
actions: {},
mutations: {
setKeyCode(state, msg) {
state.keyCode = msg
},
},
actions: {
setKeyCode({ commit }, msg) {
commit('setKeyCode', msg)
},
},
modules: {},
})
<template>
<layout class="wrap">
<div class="system-menu">
<div class="header">
<el-form
size="mini"
:inline="true"
label-width="80px"
style="margin-left: 10px"
>
<el-form-item label>
<el-button type="primary" @click="showDialog({ id: 0 }, 2)">
<el-button
type="primary"
@click="showDialog({ id: 0 }, 2)"
>
新增
</el-button>
</el-form-item>
</el-form>
<div class="table_wrap">
<my-table
</div>
<div class="table-wrap" v-loading="loading">
<table-view
:tableColumns="tableColumns"
rowKey="id"
:serialNumber="false"
:treeConfig="{ children: 'children', reserve: true }"
:treeConfig="{
children: 'children',
reserve: true,
}"
:sourceData="sourceData"
></my-table>
></table-view>
</div>
<el-dialog
......@@ -38,7 +46,10 @@
:model="editForm"
>
<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 label="父级菜单">
<el-cascader
......@@ -51,7 +62,7 @@
checkStrictly: true,
label: 'name',
value: 'id',
emitPath: false
emitPath: false,
}"
clearable
></el-cascader>
......@@ -78,15 +89,29 @@
></el-input>
</el-form-item>
<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 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 label="启用状态">
<div style="width: 164px; display: inline-block">
<el-radio v-model="editForm.enable" :label="true">启用</el-radio>
<el-radio v-model="editForm.enable" :label="false">禁用</el-radio>
<el-radio
v-model="editForm.enable"
:label="true"
>启用</el-radio
>
<el-radio
v-model="editForm.enable"
:label="false"
>禁用</el-radio
>
</div>
</el-form-item>
<el-form-item label=" 排序">
......@@ -97,29 +122,52 @@
></el-input>
</el-form-item>
<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 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>
<div slot="footer">
<el-button size="mini" @click="clone">取 消</el-button>
<el-button size="mini" type="primary" @click="submit">保 存</el-button>
<el-button size="mini" @click="clone"
>取 消</el-button
>
<el-button
size="mini"
type="primary"
@click="submit"
>保 存</el-button
>
</div>
</el-dialog>
</layout>
</div>
</template>
<script>
import { get, post } from '../utils/axios'
import MyTable from '../components/base/table.vue'
import tableView from '@/common/components/base/tableView.vue'
// import myLayout from '@/common/components/base/myLayout.vue'
import {
updateSysmenu,
getAllMenusTree,
updateMenu,
addMenu,
deleteMenu,
} from '../common/api/sys'
export default {
name: 'menu_management',
components: {
MyTable
tableView,
// myLayout,
},
data() {
return {
loading: false,
sourceData: [],
dialogVisible: false,
editForm: {
......@@ -130,12 +178,18 @@ export default {
url: '',
title: '',
describe: '',
enable: true
enable: true,
},
rules: {
type: [{ required: true, message: ' ', trigger: 'change' }]
type: [
{
required: true,
message: ' ',
trigger: 'change',
},
isEdit: false
],
},
isEdit: false,
}
},
computed: {
......@@ -146,14 +200,15 @@ export default {
key: 'name',
width: '',
align: 'left',
treeNode: true
treeNode: true,
},
{
label: '类型',
key: 'type',
width: '',
render: (item) => (item.type === 1 ? '按钮' : '菜单')
render: (item) =>
item.type === 1 ? '按钮' : '菜单',
},
{ label: '路径名称', key: 'path', width: '' },
{ label: '路径地址', key: 'route', width: '' },
......@@ -169,7 +224,7 @@ export default {
onChange={(v) => this.enableChange(item, v)}
label=""
></el-checkbox>
)
),
},
{ label: '标题', key: 'title', width: '' },
{ label: '备注', key: 'describe', width: '' },
......@@ -204,12 +259,14 @@ export default {
</el-button>
)}
</div>
)
}
),
},
]
},
showMenu() {
const data = JSON.parse(JSON.stringify(this.sourceData))
const data = JSON.parse(
JSON.stringify(this.sourceData),
)
const arr = []
for (const iterator of data) {
const children = []
......@@ -235,37 +292,34 @@ export default {
sortNo: 0,
title: '',
type: 0,
url: ''
}
url: '',
},
]
}
},
},
mounted() {
this.getlist()
// this.getlist()
},
methods: {
enableChange(item, v) {
post('sysMenu/update', {
async enableChange(item, v) {
try {
const res = await updateSysmenu({
id: item.id,
enable: v,
type: item.type
type: item.type,
})
.then((res) => {
if (res.code === 200) {
this.$message.success(res.message)
item.enable = v
}
})
.catch(() => {})
} catch (e) {
console.error(e)
}
},
// loadFunc(row, treeNode, resolve) {
// console.log(row);
// this.getlist(row.id, data => resolve(data));
// },
getlist(id, cb) {
get('sysMenu/getAllMenusTree')
.then((res) => {
async getlist(id, cb) {
this.loading = true
try {
const res = await getAllMenusTree()
if (res.code === 200) {
if (cb) {
cb(res.data)
......@@ -273,8 +327,9 @@ export default {
this.sourceData = res.data
}
}
})
.catch(() => {})
} catch (e) {
console.error(e)
}
},
resetForm() {
for (const key in this.editForm) {
......@@ -291,43 +346,51 @@ export default {
this.editForm = { ...item, enable: true }
}
this.$nextTick(() => {
this.$refs.editForm && this.$refs.editForm.clearValidate()
this.$refs.editForm &&
this.$refs.editForm.clearValidate()
})
this.dialogVisible = true
},
submit() {
this.$refs.editForm.validate((v) => {
if (v) {
const url = this.isEdit ? 'sysMenu/update' : 'sysMenu/add'
async submit() {
try {
if (!(await this.$refs.editForm.validate())) return
} catch {
return
}
const api = this.isEdit ? updateMenu : addMenu
delete this.editForm.children
post(url, {
...this.editForm
})
.then((res) => {
try {
const res = await api({ ...this.editForm })
if (res.code === 200) {
this.$message.success(res.message)
this.getlist()
}
})
.catch(() => {})
} catch (e) {
console.error(e)
} finally {
this.resetForm()
this.dialogVisible = false
}
})
},
remove(item) {
this.$confirm('确认删除?', '提示', {
async remove(item) {
try {
await this.$confirm('确认删除?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
post('sysMenu/delete/' + item.id).then((res) => {
type: 'warning',
})
} 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() {
this.resetForm()
......@@ -336,8 +399,20 @@ export default {
beforeClose(clone) {
this.resetForm()
clone()
}
}
},
},
}
</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 @@
style="width: 200px"
v-model.trim="editForm.domain"
size="small"
:disabled="!!editId"
clearable
@change="onChange"
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