feat: sys menu

pull/49/head
xingyu4j 2024-11-26 13:28:31 +08:00
parent d4bd50c36f
commit a3592c8b28
4 changed files with 298 additions and 0 deletions

View File

@ -0,0 +1,49 @@
import { requestClient } from '#/api/request';
export interface MenuVO {
id: number;
name: string;
permission: string;
type: number;
sort: number;
parentId: number;
path: string;
icon: string;
component: string;
componentName?: string;
status: number;
visible: boolean;
keepAlive: boolean;
alwaysShow?: boolean;
createTime: Date;
}
// 查询菜单(精简)列表
export function getSimpleMenusList() {
return requestClient.get('/system/menu/simple-list');
}
// 查询菜单列表
export function getMenuList(params: any) {
return requestClient.get('/system/menu/list', params);
}
// 获取菜单详情
export function getMenu(id: number) {
return requestClient.get(`/system/menu/get?id=${id}`);
}
// 新增菜单
export function createMenu(data: MenuVO) {
return requestClient.post('/system/menu/create', data);
}
// 修改菜单
export function updateMenu(data: MenuVO) {
return requestClient.put('/system/menu/update', data);
}
// 删除菜单
export function deleteMenu(id: number) {
return requestClient.delete(`/system/menu/delete?id=${id}`);
}

View File

@ -0,0 +1,54 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { useVbenForm } from '#/adapter/form';
import { createMenu, getMenu, updateMenu } from '#/api/system/menu';
import { modalSchema } from './menu.data';
defineOptions({ name: 'MenuModel' });
const isUpdate = ref(false);
const [Form, formApi] = useVbenForm({
schema: modalSchema,
handleSubmit: onSubmit,
showDefaultActions: false,
});
const [Modal, modalApi] = useVbenModal({
onCancel: async () => {
modalApi.close();
await formApi.resetForm();
},
onConfirm: async () => {
await formApi.validateAndSubmitForm();
},
async onOpenChange(isOpen: boolean) {
if (isOpen) {
const { id } = modalApi.getData<Record<string, any>>();
isUpdate.value = !!id;
if (id) {
const values = await getMenu(id);
formApi.setValues(values);
}
}
},
title: isUpdate.value ? '新增菜单' : '编辑菜单',
});
async function onSubmit(values: Record<string, any>) {
await (isUpdate.value
? updateMenu(values as any)
: createMenu(values as any));
modalApi.close();
await formApi.resetForm();
}
</script>
<template>
<Modal class="w-1/2">
<Form />
</Modal>
</template>

View File

@ -0,0 +1,122 @@
<script lang="ts" setup>
import type { VbenFormProps } from '#/adapter/form';
import type { VxeGridProps } from '#/adapter/vxe-table';
import { Page, useVbenModal } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { Button, message } from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { getMenuList, type MenuVO } from '#/api/system/menu';
import { columns, formSchema } from './menu.data';
import MenuModal from './MenuModal.vue';
defineOptions({ name: 'SystemMenu' });
const formOptions: VbenFormProps = {
//
collapsed: false,
schema: formSchema,
//
showCollapseButton: true,
//
submitOnEnter: false,
};
const gridOptions: VxeGridProps<MenuVO> = {
checkboxConfig: {
highlight: true,
labelField: 'id',
},
columns,
height: 'auto',
keepSource: true,
proxyConfig: {
ajax: {
query: async (formValues) => {
return await getMenuList({
...formValues,
});
},
},
},
pagerConfig: {
enabled: false,
},
treeConfig: {
parentField: 'parentId',
rowField: 'id',
transform: true,
},
};
const [Grid, gridApi] = useVbenVxeGrid({ formOptions, gridOptions });
const [FormModal, formModalApi] = useVbenModal({
connectedComponent: MenuModal,
});
function handleCreate() {
formModalApi.setData({
valuse: {},
});
formModalApi.open();
}
async function handleEdit(id: number) {
formModalApi.setData({ id });
formModalApi.open();
}
// TODO
function handleDelete(id: number) {
message.success(id);
}
const expandAll = () => {
gridApi.grid?.setAllTreeExpand(true);
};
const collapseAll = () => {
gridApi.grid?.setAllTreeExpand(false);
};
</script>
<template>
<Page auto-content-height>
<Grid>
<template #toolbar-actions>
<Button
type="primary"
v-access:code="['system:post:create']"
@click="handleCreate"
>
{{ $t('page.action.add') }}
</Button>
</template>
<template #toolbar-tools>
<Button class="mr-2" type="primary" @click="expandAll">
展开全部
</Button>
<Button type="primary" @click="collapseAll"> </Button>
</template>
<template #action="{ row }">
<Button
type="link"
v-access:code="['system:post:update']"
@click="handleEdit(row.id)"
>
{{ $t('page.action.edit') }}
</Button>
<Button
danger
type="link"
v-access:code="['system:post:delete']"
@click="handleDelete(row.id)"
>
{{ $t('page.action.delete') }}
</Button>
</template>
</Grid>
<FormModal />
</Page>
</template>

View File

@ -0,0 +1,73 @@
import type { VxeGridProps } from '#/adapter/vxe-table';
import { $t } from '@vben/locales';
import { type VbenFormSchema } from '#/adapter/form';
export const formSchema: VbenFormSchema[] = [
{
component: 'Input',
fieldName: 'name',
label: '菜单名称',
},
{
component: 'Input',
fieldName: 'code',
label: '岗位编码',
},
// TODO: dict
{
component: 'Select',
componentProps: {
allowClear: true,
options: [
{
label: 'Color1',
value: '1',
},
{
label: 'Color2',
value: '2',
},
],
placeholder: '请选择',
},
fieldName: 'status',
label: '状态',
},
];
export const columns: VxeGridProps['columns'] = [
// { title: '序号', type: 'seq', width: 50 },
// { field: 'id', title: '岗位编号' },
{ field: 'name', title: '菜单名称', minWidth: 200, treeNode: true },
{ field: 'icon', title: '图标' },
{ field: 'permission', title: '权限标识' },
{ field: 'component', title: '组件路径' },
{ field: 'componentName', title: '组件名称' },
{
field: 'status',
title: '状态',
cellRender: { name: 'CellDict', props: { type: 'common_status' } },
},
{ field: 'createTime', formatter: 'formatDateTime', title: '创建时间' },
{
field: 'action',
fixed: 'right',
slots: { default: 'action' },
title: $t('page.action.action'),
width: 160,
},
];
export const modalSchema: VbenFormSchema[] = [
{
component: 'Input',
fieldName: 'id',
label: 'id',
dependencies: {
triggerFields: [''],
show: () => false,
},
},
];