This commit is contained in:
王创世 2025-04-27 16:53:17 +08:00
parent bb37a7a997
commit 26b5c7e78f
7 changed files with 105 additions and 86 deletions

21
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,21 @@
{
// 使 IntelliSense
//
// 访: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "启动程序",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}\\vite.config.ts",
"outFiles": [
"${workspaceFolder}/**/*.js"
]
}
]
}

View File

@ -46,19 +46,8 @@ function refresh() {
<template #icon>
<icon-ic-round-plus class="text-icon" />
</template>
{{ $t('common.add') }}
新增
</NButton>
<NPopconfirm @positive-click="batchDelete">
<template #trigger>
<NButton size="small" ghost type="error" :disabled="disabledDelete">
<template #icon>
<icon-ic-round-delete class="text-icon" />
</template>
{{ $t('common.batchDelete') }}
</NButton>
</template>
{{ $t('common.confirmDelete') }}
</NPopconfirm>
</slot>
<NButton size="small" @click="refresh">
<template #icon>

View File

@ -191,7 +191,7 @@ init();
@contextmenu="handleContextMenu($event, tab.id)"
>
<template #prefix>
<SvgIcon :icon="tab.icon" :local-icon="tab.localIcon" class="inline-block align-text-bottom text-16px" />
<SvgIcon :icon="tab.icon" class="inline-block align-text-bottom text-16px" />
</template>
<div class="max-w-240px ellipsis-text">{{ tab.label }}</div>
</PageTab>

View File

@ -10,11 +10,12 @@ export function fetchGetUserRoutes() {
return request<Api.Route.UserRoute>({ url: '/adminapi/admin/menu?is_tree=1' });
}
/**
* whether the route is exist
*
* @param routeName route name
*/
export function fetchIsRouteExist(routeName: string) {
return request<boolean>({ url: '/route/isRouteExist', params: { routeName } });
export function getSubmitParams(item) {
return request({
url: '/adminapi/rule/add',
method: 'post',
data:item
});
}

View File

@ -4,7 +4,7 @@ import { defineStore } from 'pinia';
import { useBoolean } from '@sa/hooks';
import type { CustomRoute, ElegantConstRoute, LastLevelRouteKey, RouteKey, RouteMap } from '@elegant-router/types';
import { router } from '@/router';
import { fetchGetConstantRoutes, fetchGetUserRoutes, fetchIsRouteExist } from '@/service/api';
import { fetchGetConstantRoutes, fetchGetUserRoutes } from '@/service/api';
import { SetupStoreId } from '@/enum';
import { createStaticRoutes, getAuthVueRoutes } from '@/router/routes';
import { ROOT_ROUTE } from '@/router/routes/builtin';
@ -328,9 +328,9 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
return isRouteExistByRouteName(routeName, staticAuthRoutes);
}
const { data } = await fetchIsRouteExist(routeName);
//const { data } = await fetchIsRouteExist(routeName);
return data;
return false;
}
/**

View File

@ -20,8 +20,10 @@ declare module 'vue' {
IconAntDesignSettingOutlined: typeof import('~icons/ant-design/setting-outlined')['default']
IconGridiconsFullscreen: typeof import('~icons/gridicons/fullscreen')['default']
IconGridiconsFullscreenExit: typeof import('~icons/gridicons/fullscreen-exit')['default']
'IconIc:roundPlus': typeof import('~icons/ic/round-plus')['default']
IconIcRoundDelete: typeof import('~icons/ic/round-delete')['default']
IconIcRoundPlus: typeof import('~icons/ic/round-plus')['default']
IconIcRoundRemove: typeof import('~icons/ic/round-remove')['default']
IconLocalBanner: typeof import('~icons/local/banner')['default']
IconLocalLogo: typeof import('~icons/local/logo')['default']
IconMdiArrowDownThin: typeof import('~icons/mdi/arrow-down-thin')['default']
@ -47,9 +49,11 @@ declare module 'vue' {
NDrawer: typeof import('naive-ui')['NDrawer']
NDrawerContent: typeof import('naive-ui')['NDrawerContent']
NDropdown: typeof import('naive-ui')['NDropdown']
NDynamicInput: typeof import('naive-ui')['NDynamicInput']
NEmpty: typeof import('naive-ui')['NEmpty']
NForm: typeof import('naive-ui')['NForm']
NFormItem: typeof import('naive-ui')['NFormItem']
NFormItemGi: typeof import('naive-ui')['NFormItemGi']
NGi: typeof import('naive-ui')['NGi']
NGrid: typeof import('naive-ui')['NGrid']
NInput: typeof import('naive-ui')['NInput']
@ -64,6 +68,8 @@ declare module 'vue' {
NNotificationProvider: typeof import('naive-ui')['NNotificationProvider']
NPopconfirm: typeof import('naive-ui')['NPopconfirm']
NPopover: typeof import('naive-ui')['NPopover']
NRadio: typeof import('naive-ui')['NRadio']
NRadioGroup: typeof import('naive-ui')['NRadioGroup']
NScrollbar: typeof import('naive-ui')['NScrollbar']
NSelect: typeof import('naive-ui')['NSelect']
NSpace: typeof import('naive-ui')['NSpace']

View File

@ -8,14 +8,23 @@ import { useTable, useTableOperate } from '@/hooks/common/table';
import { $t } from '@/locales';
import { yesOrNoRecord } from '@/constants/common';
import SvgIcon from '@/components/custom/svg-icon.vue';
import { fetchGetUserRoutes } from '@/service/api/route';
import { fetchGetUserRoutes,getSubmitParams } from '@/service/api/route';
const appStore = useAppStore();
const { bool: visible, setTrue: openModal } = useBoolean();
const wrapperRef = ref<HTMLElement | null>(null);
const title=ref('');
const model = ref({
title: '',
name:'',
url:'',
condition:'',
icon:'',
weigh:'',
});
const rules = {};
const { columns, columnChecks, data, loading, pagination, getData, getDataByPage } = useTable({
apiFn: fetchGetUserRoutes,
columns: () => [
@ -66,24 +75,6 @@ const { columns, columnChecks, data, loading, pagination, getData, getDataByPage
align: 'center',
width: 200,
},
{
key: 'hideInMenu',
title: '是否隐藏',
align: 'center',
width: 120,
render: row => {
const hide: CommonType.YesOrNo = row.hideInMenu ? 'Y' : 'N';
const tagMap: Record<CommonType.YesOrNo, NaiveUI.ThemeColor> = {
Y: 'error',
N: 'default'
};
const label = $t(yesOrNoRecord[hide]);
return <NTag type={tagMap[hide]}>{label}</NTag>;
}
},
{
key: 'weigh',
title: '排序',
@ -97,7 +88,7 @@ const { columns, columnChecks, data, loading, pagination, getData, getDataByPage
width: 230,
render: row => (
<div class="flex-center justify-end gap-8px">
{row.pid ==0 && (
{row.pid == 0 && (
<NButton type="primary" ghost size="small" onClick={() => handleAddChildMenu(row)}>
添加子菜单
</NButton>
@ -110,7 +101,7 @@ const { columns, columnChecks, data, loading, pagination, getData, getDataByPage
default: () => '确定删除吗?',
trigger: () => (
<NButton type="error" ghost size="small">
'删除'
删除
</NButton>
)
}}
@ -123,10 +114,11 @@ const { columns, columnChecks, data, loading, pagination, getData, getDataByPage
const { checkedRowKeys, onBatchDeleted, onDeleted } = useTableOperate(data, getData);
const operateType = ref<OperateType>('add');
const operateType = ref('add');
function handleAdd() {
operateType.value = 'add';
title.value = '新增菜单';
openModal();
}
@ -145,72 +137,82 @@ function handleDelete(id: number) {
}
/** the edit menu data or the parent menu data when adding a child menu */
const editingData: Ref<Api.SystemManage.Menu | null> = ref(null);
const editingData = ref(null);
function handleEdit(item: Api.SystemManage.Menu) {
function handleEdit(item) {
operateType.value = 'edit';
editingData.value = { ...item };
openModal();
}
function handleAddChildMenu(item: Api.SystemManage.Menu) {
function handleAddChildMenu(item) {
operateType.value = 'addChild';
editingData.value = { ...item };
openModal();
}
const allPages = ref<string[]>([]);
async function getAllPages() {
//const { data: pages } = await fetchGetAllPages();
//allPages.value = pages || [];
}
function init() {
getAllPages();
}
// init
init();
async function handleSubmit() {
const params = getSubmitParams(model.value);
console.log('params: ', params);
// request
window.$message?.success($t('common.updateSuccess'));
visible.value=false;
}
</script>
<template>
<div ref="wrapperRef" class="flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
<NCard title="菜单管理" :bordered="false" size="small" class="sm:flex-1-hidden card-wrapper">
<template #header-extra>
<TableHeaderOperation
v-model:columns="columnChecks"
:disabled-delete="checkedRowKeys.length === 0"
:loading="loading"
@add="handleAdd"
@delete="handleBatchDelete"
@refresh="getData"
/>
<TableHeaderOperation v-model:columns="columnChecks" :disabled-delete="checkedRowKeys.length === 0"
:loading="loading" @add="handleAdd" @delete="handleBatchDelete" @refresh="getData" />
</template>
<NDataTable
v-model:checked-row-keys="checkedRowKeys"
:columns="columns"
:data="data"
size="small"
:flex-height="!appStore.isMobile"
:scroll-x="1088"
:loading="loading"
:row-key="row => row.id"
remote
:pagination="pagination"
class="sm:h-full"
/>
<MenuOperateModal
v-model:visible="visible"
:operate-type="operateType"
:row-data="editingData"
:all-pages="allPages"
@submitted="getDataByPage"
/>
<NDataTable v-model:checked-row-keys="checkedRowKeys" :columns="columns" :data="data" size="small"
:flex-height="!appStore.isMobile" :scroll-x="1088" :loading="loading" :row-key="row => row.id" remote
:pagination="pagination" class="sm:h-full" />
</NCard>
<NModal v-model:show="visible" :title="title" preset="card" class="w-800px">
<NScrollbar class="h-480px pr-20px">
<NForm ref="formRef" :model="model" :rules="rules" label-placement="left" :label-width="100">
<NGrid responsive="screen" item-responsive>
<NFormItemGi span="24" label="菜单名称" path="title">
<NInput v-model:value="model.title" placeholder="请输入菜单名称" />
</NFormItemGi>
<NFormItemGi span="24" label="路由名称" path="name">
<NInput v-model:value="model.name" placeholder="请输入路由名称" />
</NFormItemGi>
<NFormItemGi span="24" label="路由路径" path="url">
<NInput v-model:value="model.url" placeholder="请输入路由路径" />
</NFormItemGi>
<NFormItemGi span="24" label="路由组件" path="condition">
<NInput v-model:value="model.condition" placeholder="请输入路由组件" />
</NFormItemGi>
<NFormItemGi span="24 m:12" label="icon" path="icon">
<NInput v-model:value="model.icon" placeholder="请输入icon" />
</NFormItemGi>
<NFormItemGi span="24 m:12" label="排序" path="weigh">
<NInput v-model:value="model.weigh" placeholder="请输入排序" />
</NFormItemGi>
</NGrid>
</NForm>
</NScrollbar>
<template #footer>
<NSpace justify="end" :size="16">
<NButton @click="visible = false">取消</NButton>
<NButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</NButton>
</NSpace>
</template>
</NModal>
</div>
</template>