ソースを参照

restructure menu

tags/v1.0.0^2
zhangtao 2年前
コミット
3e6dddfaec
10個のファイルの変更378行の追加405行の削除
  1. +20
    -0
      src/utils/dictionary.js
  2. +5
    -5
      src/views/system-manage/department-manage/components/DepartmentModal.vue
  3. +88
    -166
      src/views/system-manage/menu-manage/components/MenuModal.vue
  4. +13
    -126
      src/views/system-manage/menu-manage/index.vue
  5. +0
    -101
      src/views/system-manage/menu-manage/table.js
  6. +53
    -0
      src/views/system-manage/menu-manage/tools/form.js
  7. +3
    -2
      src/views/system-manage/menu-manage/tools/search.js
  8. +191
    -0
      src/views/system-manage/menu-manage/tools/table.js
  9. +3
    -3
      src/views/system-manage/role-manage/components/ConfigModal.vue
  10. +2
    -2
      src/views/system-manage/role-manage/tools/table.js

+ 20
- 0
src/utils/dictionary.js ファイルの表示

@@ -25,3 +25,23 @@ export const USER_STATUS = [
{ label: '正常', value: 1 },
{ label: '禁用', value: 2 }
]

export const MENU_TYPE = [
{ label: '菜单', value: 0 },
{ label: '按钮', value: 1 }
]

export const MENU_OPEN = [
{ label: '内部', value: '1' },
{ label: '外部', value: '2' }
]

export const MENU_VISIBLE = [
{ label: '可见', value: 0 },
{ label: '不可见', value: 1 }
]

export const MENU_STATUS = [
{ label: '在用', value: 1 },
{ label: '停用', value: 2 }
]

+ 5
- 5
src/views/system-manage/department-manage/components/DepartmentModal.vue ファイルの表示

@@ -93,12 +93,12 @@ export default defineComponent({
function handleConfirm() {
formRef.value.validate((errors) => {
if (!errors) {
const params = { ...data.roleForm }
const params = { ...data.departmentForm }
if (params.id) {
editDept(params).then(res => {
if (res.code === 0) {
this.handleClose()
this.$emit('reload')
handleClose()
emit('reload')
}
}).catch(e => {
console.log(e)
@@ -106,8 +106,8 @@ export default defineComponent({
} else {
addDept(params).then(res => {
if (res.code === 0) {
this.handleClose()
this.$emit('reload')
handleClose()
emit('reload')
}
})
}

+ 88
- 166
src/views/system-manage/menu-manage/components/MenuModal.vue ファイルの表示

@@ -6,223 +6,131 @@
:on-negative-click="handleClose"
>
<template #Context>
<n-form ref="formRef" :model="form" :rules="rules" require-mark-placement="left" :label-width="80" label-placement="left">
<n-form
ref="formRef"
:model="menuForm"
:rules="menuRules"
:label-width="80"
label-placement="left"
require-mark-placement="left"
:disabled="disabled"
>
<n-grid x-gap="12" :cols="2">
<n-gi>
<n-form-item label="上级菜单" path="pid">
<n-select
v-model:value="form.pid"
:options="getMenuList"
placeholder="请选择上级菜单"
/>
</n-form-item>
</n-gi>
<n-gi>
<n-form-item label="菜单类型" path="type">
<n-radio-group v-model:value="form.type" name="type">
<n-radio v-for="item in typeOptions" :key="item.key" :value="item.key">
{{ item.label }}
</n-radio>
</n-radio-group>
</n-form-item>
</n-gi>
<n-gi>
<n-form-item label="菜单名称" path="title">
<n-input v-model:value="form.title" placeholder="请输入菜单名称" />
</n-form-item>
</n-gi>
<n-gi>
<n-form-item label="打开方式" path="target">
<n-radio-group v-model:value="form.target" name="target">
<n-radio v-for="item in openOptions" :key="item.key" :value="item.key">
{{ item.label }}
</n-radio>
</n-radio-group>
</n-form-item>
</n-gi>
<n-gi>
<n-form-item label="菜单图标" path="icon">
<n-input v-model:value="form.icon" :disabled="form.type === 1" placeholder="请选择菜单图标" />
</n-form-item>
</n-gi>
<n-gi>
<n-form-item label="权限标识" path="permission">
<n-input v-model:value="form.permission" :disabled="form.type === 0" placeholder="请输入权限标识" />
</n-form-item>
</n-gi>
<n-gi>
<n-form-item label="路由地址" path="path">
<n-input v-model:value="form.path" :disabled="form.type === 1" placeholder="请输入路由地址" />
</n-form-item>
</n-gi>
<n-gi>
<n-form-item label="排序号" path="sort">
<n-input-number v-model:value="form.sort" placeholder="请输入排序号" />
</n-form-item>
</n-gi>
<n-gi>
<n-form-item label="组件路径" path="component">
<n-input v-model:value="form.component" :disabled="form.type === 1" placeholder="请输入组件路径" />
</n-form-item>
</n-gi>
<n-gi>
<n-form-item label="是否可见" path="hide">
<n-radio-group v-model:value="form.hide" name="hide">
<n-radio v-for="item in visibleOptions" :key="item.key" :value="item.key">
{{ item.label }}
</n-radio>
</n-radio-group>
</n-form-item>
</n-gi>
<n-gi>
<n-form-item label="菜单状态" path="status">
<n-radio-group v-model:value="form.status" name="status">
<n-radio v-for="item in statusOptions" :key="item.key" :value="item.key">
{{ item.label }}
</n-radio>
</n-radio-group>
</n-form-item>
</n-gi>

<template v-for="(item,index) in getFormOptions" :key="index">
<n-gi>
<n-form-item :label="item.label" :path="item.key">
<n-input v-if="item.type === 'input'" v-model:value="menuForm[item.key]" v-bind="item.props" />
<n-select v-if="item.type === 'select'" v-model:value="menuForm[item.key]" v-bind="item.props" />
<n-input-number v-if="item.type === 'number'" v-model:value="menuForm[item.key]" v-bind="item.props" />
<n-radio-group v-if="item.type === 'radio'" v-model:value="menuForm[item.key]" :name="item.key">
<n-space>
<n-radio v-for="(cItem,cIndex) in item.options" :key="`${item.key}_${cIndex}`" :value="cItem.value"> {{ cItem.label }}</n-radio>
</n-space>
</n-radio-group>
</n-form-item>
</n-gi>
</template>
</n-grid>

</n-form>
</template>
</Modal>
</template>

<script>
import { defineComponent, computed, reactive, toRefs } from 'vue'
import { form, changeMenuType, getMenuOptions } from '../tools/form.js'
import { defineComponent, ref, reactive, computed, watch, toRefs } from 'vue'
import Modal from '@/components/Modal/index.vue'
import { addMenu, editMenu } from '@/api/system/menu/index.js'
export default defineComponent({
name: 'MenuModal',
components: { Modal },
props: {
/* 可见 */
visible: {
type: Boolean,
default: false
},
/* 选中的数据 */
type: {
type: String,
default: 'create'
},
data: {
type: Object,
default: () => {}
},
menuList: {
type: Array,
default: () => []
}
},
emits: {
'update:visible': null,
'done': null
'reload': null
},
setup(props, { emit }) {
const MODAL_TYPE = {
'create': '新建菜单',
'preview': '菜单详情',
'update': '编辑菜单'
}
getMenuOptions()
const { menuForm, menuRules } = form
const formRef = ref()
const data = reactive({
form: {
title: '',
icon: '',
permission: '',
path: '',
component: '',
hide: 0,
status: 1
menuForm: {
...menuForm,
...props.data,
pid: props.data?.pid === 0 ? null : props.data?.pid
},
rules: {
title: [{
required: true,
message: '请输入菜单名称',
trigger: 'blur'
}],
sort: [{
required: true,
type: 'number',
message: '请输入排序号',
trigger: 'blur'
}]
menuRules: {
...menuRules
},
typeOptions: [
{ key: 0, label: '菜单' },
{ key: 1, label: '按钮' }
],
openOptions: [
{ key: '1', label: '内部' },
{ key: '2', label: '外部' }
],
visibleOptions: [
{ key: 0, label: '可见' },
{ key: 1, label: '不可见' }
],
statusOptions: [
{ key: 1, label: '在用' },
{ key: 2, label: '停用' }
]
disabled: props.type === 'preview'
})

const getMenuList = computed(() => {
const list = props.menuList.map((item) => {
const menu = {
label: item.title,
value: item.id
watch(() => data.menuForm.type,
(val) => {
switch (val) {
case 0:
data.menuForm.permission = ''
break
case 1:
data.menuForm.path = ''
data.menuForm.component = ''
break
}
return menu
changeMenuType(val)
})
return list
})

const getModalOptions = computed(() => {
const row = props.data
if (props.data.pid === 0) {
row.pid = null
}
console.log('菜单页面计算属性触发:', row)
return {
title: props.data.title ? '修改菜单' : '添加菜单',
title: MODAL_TYPE[props.type],
show: props.visible,
form: Object.assign(data.form, row),
negativeText: '取消',
positiveText: '确认'
}
})

/* 关闭弹窗 */
const handleClose = () => {
emit('update:visible', false)
}
const getFormOptions = computed(() => {
console.log('change')
return {
...form.formItem
}
})

return {
...toRefs(data),
getMenuList,
getModalOptions,
handleClose
}
},
methods: {
// 表单提交
handleConfirm() {
const type = this.data.title ? 'edit' : 'add'
this.$refs.formRef.validate((errors) => {
function handleConfirm() {
formRef.value.validate((errors) => {
if (!errors) {
if (type === 'add') {
addMenu(this.form).then(res => {
const params = { ...data.menuForm }
if (params.id) {
editMenu(params).then(res => {
if (res.code === 0) {
this.handleClose()
this.$emit('done')
$message.success(res.msg)
} else {
$message.error(res.msg)
emit('reload')
}
}).catch(e => {
console.log(e)
})
} else if (type === 'edit') {
editMenu(this.form).then(res => {
} else {
addMenu(params).then(res => {
if (res.code === 0) {
this.handleClose()
this.$emit('done')
$message.success(res.msg)
} else {
$message.error(res.msg)
handleClose()
emit('reload')
}
})
}
@@ -231,6 +139,20 @@ export default defineComponent({
}
})
}

/* 关闭弹窗 */
const handleClose = () => {
emit('update:visible', false)
}

return {
...toRefs(data),
formRef,
getModalOptions,
getFormOptions,
handleConfirm,
handleClose
}
}
})
</script>

+ 13
- 126
src/views/system-manage/menu-manage/index.vue ファイルの表示

@@ -1,7 +1,7 @@
<template>
<div>
<n-card>
<headSearch :info="info" @search="handleSearch" />
<headSearch :info="search" @search="handleSearch" @reset="handleSearch" />
<data-table
ref="tableRef"
:columns="columns"
@@ -17,110 +17,30 @@
</n-card>
</div>

<MenuModal
v-if="modalShow"
v-model:visible="modalShow"
:data="rowData"
:menu-list="menuList"
@done="handleSearch"
/>
<MenuModal v-if="modalShow" v-model:visible="modalShow" :data="rowData" :type="modalType" @reload="handleSearch" />
</template>

<script>
import search from './tools/search.js'
import table from './tools/table.js'
import headSearch from '@/components/Search/index.vue'
import dataTable from '@/components/DataTable/index.vue'
import MenuModal from './components/MenuModal.vue'
import Action from '@/components/DataTable/tools/Action.vue'
import { getMenu, getMenuList, deleteMenu } from '@/api/system/menu/index.js'
import { h, ref, unref, reactive, toRefs, onMounted } from 'vue'
import info from './info.js'
import table from './table.js'
import { getMenuList } from '@/api/system/menu/index.js'
import { unref, reactive, toRefs } from 'vue'

export default {
name: 'MenuPage',
components: { dataTable, MenuModal, headSearch },
setup() {
const data = reactive({
columns: [
...table.columns,
{
title: '操作',
align: 'center',
width: 150,
fixed: 'right',
render(row) {
return h(Action, {
actions: [
{
label: '添加',
type: 'button',
props: {
type: 'primary',
onClick: add.bind(null, row)
},
auth: 'basic_list'
},
{
label: '修改',
type: 'button',
props: {
type: 'primary',
onClick: play.bind(null, row)
},
auth: 'basic_list'
},
{
label: '删除',
type: 'popconfirm',
auth: 'basic_list',
tip: '确定删除这条数据吗?',
props: {
negativeText: '取消',
positiveText: '确认',
onPositiveClick: deleteSingle.bind(null, row.id)
}
}
],
align: 'center'
})
}
}
],
info: ref(info),
modalShow: false,
menuList: [],
rowData: {
status: 1,
type: 0,
hide: 0
}
})

// 获取全部菜单信息
async function getMenuAll() {
const list = await getMenu()
data.menuList = list.data
}
onMounted(() => {
getMenuAll()
...toRefs(table),
search
})

/**
* @description: 获取菜单数据
* @return {*}
*/
const params = ref({})
const tableRef = ref()

function handleSearch(data) {
params.value = {
...data
}
tableRef.value.reFetch({ ...unref(params) })
}

const loadDataTable = async(res) => {
const _params = {
...unref(params),
...unref(data.searchParams),
...res
}
return await getMenuList(_params)
@@ -128,48 +48,15 @@ export default {

// 打开新增弹框
function handleModal() {
data.rowData = null
data.modalType = 'create'
data.modalShow = true
data.rowData = {}
}
// 行内新增
function add(row) {
data.modalShow = true
data.rowData = {}
data.rowData.pid = row.id
}
// 编辑
function play(row) {
data.rowData = row
data.modalShow = true
}
// 单个删除数据
function deleteSingle(id) {
deleteData(id)
}

// 删除方法
function deleteData(id) {
deleteMenu(id)
.then((res) => {
if (res.code === 0) {
handleSearch({})
$message.success(res.msg)
} else {
$message.error(res.msg)
}
})
.catch((e) => {
console.log(e)
})
}

return {
...toRefs(data),
tableRef,
loadDataTable,
handleSearch,
handleModal,
deleteSingle
handleModal
}
}
}

+ 0
- 101
src/views/system-manage/menu-manage/table.js ファイルの表示

@@ -1,101 +0,0 @@
import { h } from 'vue'
import TableTags from '@/components/DataTable/tools/Tags.vue'
const table = {
columns: [
{
title: '菜单标题',
key: 'title',
align: 'center',
width: 200
},
{
title: '菜单类型',
key: 'type',
align: 'center',
width: 100,
render(row) {
return h(TableTags, {
data: row.type,
filters: [
{
key: 0,
label: '菜单'
},
{
key: 1,
label: '节点'
}
]
})
}
},
{
title: '路由地址',
key: 'path',
align: 'center',
width: 200
},
{
title: '组件路径',
key: 'component',
align: 'center',
width: 200
},
{
title: '状态',
key: 'status',
align: 'center',
width: 100,
render(row) {
return h(TableTags, {
data: row.status,
filters: [
{
key: 1,
label: '在用'
},
{
key: 2,
label: '停用'
}
]
})
}
},
{
title: '排序',
key: 'sort',
align: 'center',
width: 100
},
{
title: '是否可见',
key: 'hide',
align: 'center',
width: 100,
render(row) {
return h(TableTags, {
data: row.hide,
filters: [
{
key: 1,
label: '可见'
},
{
key: 2,
label: '不可见'
}
]
})
}
},
{
title: '创建时间',
key: 'createTime',
align: 'center',
width: 160
}
]
}

export default table

+ 53
- 0
src/views/system-manage/menu-manage/tools/form.js ファイルの表示

@@ -0,0 +1,53 @@
import { ref, reactive, watch } from 'vue'
import { MENU_TYPE, MENU_OPEN, MENU_VISIBLE, MENU_STATUS } from '@/utils/dictionary.js'
import { getMenu } from '@/api/system/menu/index.js'
import { dataToSelect } from '@/utils/handleData.js'
const menuOptions = ref()
const menuType0 = ref(true)
const menuType1 = ref(false)

export const form = reactive({
menuForm: {
pid: null,
type: 0,
title: '',
target: '1',
icon: '',
permission: '',
path: '',
sort: null,
component: '',
hide: 0,
status: 1
},
menuRules: {
title: [{ required: true, message: '请输入菜单名称', trigger: 'blur' }],
sort: [{ required: true, type: 'number', message: '请输入排序号', trigger: 'blur' }]
},
formItem: [
{ type: 'select', key: 'pid', label: '上级菜单', props: { options: menuOptions, placeholder: '请选择上级菜单' }},
{ type: 'radio', key: 'type', label: '菜单类型', options: MENU_TYPE },
{ type: 'input', key: 'title', label: '菜单名称', props: { maxlength: '20', placeholder: '请输入菜单名称', clearable: true }},
{ type: 'radio', key: 'target', label: '打开方式', options: MENU_OPEN },
{ type: 'input', key: 'icon', label: '菜单图标', props: { maxlength: '20', placeholder: '请选择菜单图标', clearable: true }},
{ type: 'input', key: 'permission', label: '权限标识', props: { maxlength: '20', placeholder: '请输入部门名称', disabled: menuType0, clearable: true }},
{ type: 'input', key: 'path', label: '路由地址', props: { maxlength: '20', placeholder: '请输入部门名称', disabled: menuType1, clearable: true }},
{ type: 'number', key: 'sort', label: '排序号', props: { min: 0, placeholder: '请输入排序号', clearable: true }},
{ type: 'input', key: 'component', label: '组件路径', props: { maxlength: '20', placeholder: '请输入部门名称', disabled: menuType1, clearable: true }},
{ type: 'radio', key: 'hide', label: '是否可见', options: MENU_VISIBLE },
{ type: 'radio', key: 'status', label: '菜单状态', options: MENU_STATUS }
]
})

export const getMenuOptions = async function() {
const res = await getMenu()
setTimeout(() => {
menuOptions.value = dataToSelect(res.data, { label: 'title', value: 'id' })
}, 3000)
}

export const changeMenuType = function(value) {
menuType0.value = !value
menuType1.value = !menuType0.value
}


src/views/system-manage/menu-manage/info.js → src/views/system-manage/menu-manage/tools/search.js ファイルの表示

@@ -1,4 +1,5 @@
const data = [
import { reactive } from 'vue'
const data = reactive([
{
label: '菜单名称',
key: 'title',
@@ -6,7 +7,7 @@ const data = [
placeholder: '请输入菜单名称'
}
}
]
])

export default data


+ 191
- 0
src/views/system-manage/menu-manage/tools/table.js ファイルの表示

@@ -0,0 +1,191 @@
import { h, ref, reactive } from 'vue'
import TableTags from '@/components/DataTable/tools/Tags.vue'
import TableAction from '@/components/DataTable/tools/Action.vue'
import { deleteMenu } from '@/api/system/menu/index.js'

/* 注册table */
const tableRef = ref()
const searchParams = ref()

function handleSearch(params) {
searchParams.value = { ...params }
tableRef.value.reFetch({ searchParams })
}

/**
* @description: 获取数据及操作
* @param {*} row 单行数据
* @param {*} type 操作类型 create:创建,preview:预览,edit:编辑
* @return {*}
*/
function getRowData(row, type) {
data.rowData = type === 'create' ? { pid: row.id } : row
data.modalType = type
data.modalShow = true
}

// 删除方法
function deleteData(id) {
deleteMenu(id)
.then((res) => {
if (res.code === 0) {
handleSearch()
}
})
.catch((e) => {
console.log(e)
})
}

const data = reactive({
tableRef,
searchParams,
rowData: {},
modalType: 'create',
modalShow: false,
handleSearch,

columns: [
{
title: '菜单标题',
key: 'title',
align: 'center',
width: 200
},
{
title: '菜单类型',
key: 'type',
align: 'center',
width: 100,
render(row) {
return h(TableTags, {
data: row.type,
filters: [
{
key: 0,
label: '菜单'
},
{
key: 1,
label: '节点'
}
]
})
}
},
{
title: '路由地址',
key: 'path',
align: 'center',
width: 200
},
{
title: '组件路径',
key: 'component',
align: 'center',
width: 200
},
{
title: '状态',
key: 'status',
align: 'center',
width: 100,
render(row) {
return h(TableTags, {
data: row.status,
filters: [
{
key: 1,
label: '在用'
},
{
key: 2,
label: '停用'
}
]
})
}
},
{
title: '排序',
key: 'sort',
align: 'center',
width: 100
},
{
title: '是否可见',
key: 'hide',
align: 'center',
width: 100,
render(row) {
return h(TableTags, {
data: row.hide,
filters: [
{
key: 1,
label: '可见'
},
{
key: 2,
label: '不可见'
}
]
})
}
},
{
title: '创建时间',
key: 'createTime',
align: 'center',
width: 160
},
{
title: '操作',
align: 'center',
width: 150,
fixed: 'right',
render(row) {
return h(TableAction, {
actions: [
{
label: '添加',
type: 'button',
props: {
type: 'primary',
text: true,
onClick: getRowData.bind(null, row, 'create')
},
auth: 'basic_list'
},
{
label: '修改',
type: 'button',
props: {
type: 'primary',
text: true,
onClick: getRowData.bind(null, row, 'update')
},
auth: 'basic_list'
},
{
label: '删除',
type: 'popconfirm',
auth: 'basic_list',
tip: '确定删除这条数据吗?',
props: {
onPositiveClick: deleteData.bind(null, [row.id])
},
ButtonProps: {
text: true,
type: 'primary'
}
}
],
align: 'center'
})
}
}
]
})

export default data

+ 3
- 3
src/views/system-manage/role-manage/components/ConfigModal.vue ファイルの表示

@@ -81,10 +81,10 @@ export default defineComponent({
}

function handleConfirm() {
savePermission({ roleId: this.row.id, menuIds: this.menuIds }).then(res => {
savePermission({ roleId: props.data.id, menuIds: data.menuIds }).then(res => {
if (res.code === 0) {
this.handleClose()
this.$emit('reload')
handleClose()
emit('reload')
}
}).catch(e => {
console.log(e)

+ 2
- 2
src/views/system-manage/role-manage/tools/table.js ファイルの表示

@@ -1,7 +1,7 @@
import { h, ref, reactive } from 'vue'
import TableSwitch from '@/components/DataTable/tools/Switch.vue'
import TableAction from '@/components/DataTable/tools/Action.vue'
import { getRoleList, deleteRole, setRoleStatus } from '@/api/system/role/index'
import { deleteRole, setRoleStatus } from '@/api/system/role/index'

/* 注册table */
const tableRef = ref()
@@ -108,7 +108,7 @@ const data = reactive({
rowKey: 'status',
checkedValue: 1,
uncheckedValue: 2,
onChange: handleStatusChange.bind(null, row)
onChange: handleStatusChange.bind(row)
})
}
},

読み込み中…
キャンセル
保存