From 1054eec9d119996443f30c21d878aca10846ec36 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Sun, 15 Jun 2025 15:11:19 +0800 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=E3=80=90antd=E3=80=91=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E6=89=B9=E9=87=8F=E5=88=A0=E9=99=A4=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web-antd/src/api/infra/codegen/index.ts | 7 +++ apps/web-antd/src/api/infra/config/index.ts | 5 ++ .../src/api/infra/file-config/index.ts | 7 +++ apps/web-antd/src/api/infra/file/index.ts | 5 ++ apps/web-antd/src/api/infra/job/index.ts | 5 ++ apps/web-antd/src/views/infra/codegen/data.ts | 1 + .../src/views/infra/codegen/index.vue | 41 +++++++++++++++ apps/web-antd/src/views/infra/config/data.ts | 1 + .../web-antd/src/views/infra/config/index.vue | 50 ++++++++++++++++++- apps/web-antd/src/views/infra/file/data.ts | 1 + apps/web-antd/src/views/infra/file/index.vue | 45 ++++++++++++++++- .../src/views/infra/fileConfig/data.ts | 1 + .../src/views/infra/fileConfig/index.vue | 44 +++++++++++++++- apps/web-antd/src/views/infra/job/data.ts | 1 + apps/web-antd/src/views/infra/job/index.vue | 41 ++++++++++++++- 15 files changed, 248 insertions(+), 7 deletions(-) diff --git a/apps/web-antd/src/api/infra/codegen/index.ts b/apps/web-antd/src/api/infra/codegen/index.ts index 1c2d97ba3..4fe35b047 100644 --- a/apps/web-antd/src/api/infra/codegen/index.ts +++ b/apps/web-antd/src/api/infra/codegen/index.ts @@ -148,3 +148,10 @@ export function deleteCodegenTable(tableId: number) { params: { tableId }, }); } + +/** 批量删除代码生成表定义 */ +export function deleteCodegenTableList(tableIds: number[]) { + return requestClient.delete( + `/infra/codegen/delete-list?tableIds=${tableIds.join(',')}`, + ); +} diff --git a/apps/web-antd/src/api/infra/config/index.ts b/apps/web-antd/src/api/infra/config/index.ts index 3911e01c7..521e957a2 100644 --- a/apps/web-antd/src/api/infra/config/index.ts +++ b/apps/web-antd/src/api/infra/config/index.ts @@ -54,6 +54,11 @@ export function deleteConfig(id: number) { return requestClient.delete(`/infra/config/delete?id=${id}`); } +/** 批量删除参数 */ +export function deleteConfigList(ids: number[]) { + return requestClient.delete(`/infra/config/delete-list?ids=${ids.join(',')}`); +} + /** 导出参数 */ export function exportConfig(params: any) { return requestClient.download('/infra/config/export', { diff --git a/apps/web-antd/src/api/infra/file-config/index.ts b/apps/web-antd/src/api/infra/file-config/index.ts index a16cf2bc0..20a0ab3fa 100644 --- a/apps/web-antd/src/api/infra/file-config/index.ts +++ b/apps/web-antd/src/api/infra/file-config/index.ts @@ -69,6 +69,13 @@ export function deleteFileConfig(id: number) { return requestClient.delete(`/infra/file-config/delete?id=${id}`); } +/** 批量删除文件配置 */ +export function deleteFileConfigList(ids: number[]) { + return requestClient.delete( + `/infra/file-config/delete-list?ids=${ids.join(',')}`, + ); +} + /** 测试文件配置 */ export function testFileConfig(id: number) { return requestClient.get(`/infra/file-config/test?id=${id}`); diff --git a/apps/web-antd/src/api/infra/file/index.ts b/apps/web-antd/src/api/infra/file/index.ts index a399db67d..edf06933b 100644 --- a/apps/web-antd/src/api/infra/file/index.ts +++ b/apps/web-antd/src/api/infra/file/index.ts @@ -45,6 +45,11 @@ export function deleteFile(id: number) { return requestClient.delete(`/infra/file/delete?id=${id}`); } +/** 批量删除文件 */ +export function deleteFileList(ids: number[]) { + return requestClient.delete(`/infra/file/delete-list?ids=${ids.join(',')}`); +} + /** 获取文件预签名地址 */ export function getFilePresignedUrl(name: string, directory?: string) { return requestClient.get( diff --git a/apps/web-antd/src/api/infra/job/index.ts b/apps/web-antd/src/api/infra/job/index.ts index bacdbc4a1..05f6a727f 100644 --- a/apps/web-antd/src/api/infra/job/index.ts +++ b/apps/web-antd/src/api/infra/job/index.ts @@ -46,6 +46,11 @@ export function deleteJob(id: number) { return requestClient.delete(`/infra/job/delete?id=${id}`); } +/** 批量删除定时任务调度 */ +export function deleteJobList(ids: number[]) { + return requestClient.delete(`/infra/job/delete-list?ids=${ids.join(',')}`); +} + /** 导出定时任务调度 */ export function exportJob(params: any) { return requestClient.download('/infra/job/export-excel', { params }); diff --git a/apps/web-antd/src/views/infra/codegen/data.ts b/apps/web-antd/src/views/infra/codegen/data.ts index a2b50d9c3..928f27009 100644 --- a/apps/web-antd/src/views/infra/codegen/data.ts +++ b/apps/web-antd/src/views/infra/codegen/data.ts @@ -394,6 +394,7 @@ export function useGridColumns( getDataSourceConfigName?: (dataSourceConfigId: number) => string | undefined, ): VxeTableGridOptions['columns'] { return [ + { type: 'checkbox', width: 40 }, { field: 'dataSourceConfigId', title: '数据源', diff --git a/apps/web-antd/src/views/infra/codegen/index.vue b/apps/web-antd/src/views/infra/codegen/index.vue index 88bb7b438..aa18e56eb 100644 --- a/apps/web-antd/src/views/infra/codegen/index.vue +++ b/apps/web-antd/src/views/infra/codegen/index.vue @@ -7,12 +7,14 @@ import { ref } from 'vue'; import { useRouter } from 'vue-router'; import { Page, useVbenModal } from '@vben/common-ui'; +import { isEmpty } from '@vben/utils'; import { message } from 'ant-design-vue'; import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; import { deleteCodegenTable, + deleteCodegenTableList, downloadCodegen, getCodegenTablePage, syncCodegenFromDB, @@ -83,6 +85,31 @@ async function handleDelete(row: InfraCodegenApi.CodegenTable) { } } +const checkedIds = ref([]); +function handleRowCheckboxChange({ + records, +}: { + records: InfraCodegenApi.CodegenTable[]; +}) { + checkedIds.value = records.map((item) => item.id); +} + +/** 批量删除代码生成配置 */ +async function handleDeleteBatch() { + const hideLoading = message.loading({ + content: $t('ui.actionMessage.deleting'), + duration: 0, + key: 'action_process_msg', + }); + try { + await deleteCodegenTableList(checkedIds.value); + message.success($t('ui.actionMessage.deleteSuccess')); + onRefresh(); + } finally { + hideLoading(); + } +} + /** 同步数据库 */ async function handleSync(row: InfraCodegenApi.CodegenTable) { const hideLoading = message.loading({ @@ -146,12 +173,17 @@ const [Grid, gridApi] = useVbenVxeGrid({ }, rowConfig: { keyField: 'id', + isHover: true, }, toolbarConfig: { refresh: { code: 'query' }, search: true, }, } as VxeTableGridOptions, + gridEvents: { + checkboxAll: handleRowCheckboxChange, + checkboxChange: handleRowCheckboxChange, + }, }); /** 获取数据源配置列表 */ @@ -197,6 +229,15 @@ initDataSourceConfig(); auth: ['infra:codegen:create'], onClick: handleImport, }, + { + label: '批量删除', + type: 'primary', + danger: true, + disabled: isEmpty(checkedIds), + icon: ACTION_ICON.DELETE, + auth: ['infra:codegen:delete'], + onClick: handleDeleteBatch, + }, ]" /> diff --git a/apps/web-antd/src/views/infra/config/data.ts b/apps/web-antd/src/views/infra/config/data.ts index ae886c47f..612b00cec 100644 --- a/apps/web-antd/src/views/infra/config/data.ts +++ b/apps/web-antd/src/views/infra/config/data.ts @@ -119,6 +119,7 @@ export function useGridFormSchema(): VbenFormSchema[] { /** 列表的字段 */ export function useGridColumns(): VxeTableGridOptions['columns'] { return [ + { type: 'checkbox', width: 40 }, { field: 'id', title: '参数主键', diff --git a/apps/web-antd/src/views/infra/config/index.vue b/apps/web-antd/src/views/infra/config/index.vue index 9d4d6d0ca..b1950e6ac 100644 --- a/apps/web-antd/src/views/infra/config/index.vue +++ b/apps/web-antd/src/views/infra/config/index.vue @@ -2,13 +2,20 @@ import type { VxeTableGridOptions } from '#/adapter/vxe-table'; import type { InfraConfigApi } from '#/api/infra/config'; +import { ref } from 'vue'; + import { Page, useVbenModal } from '@vben/common-ui'; -import { downloadFileFromBlobPart } from '@vben/utils'; +import { downloadFileFromBlobPart, isEmpty } from '@vben/utils'; import { message } from 'ant-design-vue'; import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; -import { deleteConfig, exportConfig, getConfigPage } from '#/api/infra/config'; +import { + deleteConfig, + deleteConfigList, + exportConfig, + getConfigPage, +} from '#/api/infra/config'; import { $t } from '#/locales'; import { useGridColumns, useGridFormSchema } from './data'; @@ -59,6 +66,31 @@ async function handleDelete(row: InfraConfigApi.Config) { } } +const checkedIds = ref([]); +function handleRowCheckboxChange({ + records, +}: { + records: InfraConfigApi.Config[]; +}) { + checkedIds.value = records.map((item) => item.id as number); +} + +/** 批量删除参数 */ +async function handleDeleteBatch() { + const hideLoading = message.loading({ + content: $t('ui.actionMessage.deleting'), + duration: 0, + key: 'action_process_msg', + }); + try { + await deleteConfigList(checkedIds.value); + message.success($t('ui.actionMessage.deleteSuccess')); + onRefresh(); + } finally { + hideLoading(); + } +} + const [Grid, gridApi] = useVbenVxeGrid({ formOptions: { schema: useGridFormSchema(), @@ -80,12 +112,17 @@ const [Grid, gridApi] = useVbenVxeGrid({ }, rowConfig: { keyField: 'id', + isHover: true, }, toolbarConfig: { refresh: { code: 'query' }, search: true, }, } as VxeTableGridOptions, + gridEvents: { + checkboxAll: handleRowCheckboxChange, + checkboxChange: handleRowCheckboxChange, + }, }); @@ -110,6 +147,15 @@ const [Grid, gridApi] = useVbenVxeGrid({ auth: ['infra:config:export'], onClick: handleExport, }, + { + label: '批量删除', + type: 'primary', + danger: true, + disabled: isEmpty(checkedIds), + icon: ACTION_ICON.DELETE, + auth: ['infra:config:delete'], + onClick: handleDeleteBatch, + }, ]" /> diff --git a/apps/web-antd/src/views/infra/file/data.ts b/apps/web-antd/src/views/infra/file/data.ts index 3b9eecb1e..532939559 100644 --- a/apps/web-antd/src/views/infra/file/data.ts +++ b/apps/web-antd/src/views/infra/file/data.ts @@ -54,6 +54,7 @@ export function useGridFormSchema(): VbenFormSchema[] { /** 列表的字段 */ export function useGridColumns(): VxeTableGridOptions['columns'] { return [ + { type: 'checkbox', width: 40 }, { field: 'name', title: '文件名', diff --git a/apps/web-antd/src/views/infra/file/index.vue b/apps/web-antd/src/views/infra/file/index.vue index 6d55c4098..b9df5e8a6 100644 --- a/apps/web-antd/src/views/infra/file/index.vue +++ b/apps/web-antd/src/views/infra/file/index.vue @@ -2,14 +2,16 @@ import type { VxeTableGridOptions } from '#/adapter/vxe-table'; import type { InfraFileApi } from '#/api/infra/file'; +import { ref } from 'vue'; + import { Page, useVbenModal } from '@vben/common-ui'; -import { openWindow } from '@vben/utils'; +import { isEmpty, openWindow } from '@vben/utils'; import { useClipboard } from '@vueuse/core'; import { Button, Image, message } from 'ant-design-vue'; import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; -import { deleteFile, getFilePage } from '#/api/infra/file'; +import { deleteFile, deleteFileList, getFilePage } from '#/api/infra/file'; import { $t } from '#/locales'; import { useGridColumns, useGridFormSchema } from './data'; @@ -64,6 +66,31 @@ async function handleDelete(row: InfraFileApi.File) { } } +const checkedIds = ref([]); +function handleRowCheckboxChange({ + records, +}: { + records: InfraFileApi.File[]; +}) { + checkedIds.value = records.map((item) => item.id as number); +} + +/** 批量删除文件 */ +async function handleDeleteBatch() { + const hideLoading = message.loading({ + content: $t('ui.actionMessage.deleting'), + duration: 0, + key: 'action_process_msg', + }); + try { + await deleteFileList(checkedIds.value); + message.success($t('ui.actionMessage.deleteSuccess')); + onRefresh(); + } finally { + hideLoading(); + } +} + const [Grid, gridApi] = useVbenVxeGrid({ formOptions: { schema: useGridFormSchema(), @@ -85,12 +112,17 @@ const [Grid, gridApi] = useVbenVxeGrid({ }, rowConfig: { keyField: 'id', + isHover: true, }, toolbarConfig: { refresh: { code: 'query' }, search: true, }, } as VxeTableGridOptions, + gridEvents: { + checkboxAll: handleRowCheckboxChange, + checkboxChange: handleRowCheckboxChange, + }, }); @@ -108,6 +140,15 @@ const [Grid, gridApi] = useVbenVxeGrid({ auth: ['infra:file:create'], onClick: handleUpload, }, + { + label: '批量删除', + type: 'primary', + danger: true, + disabled: isEmpty(checkedIds), + icon: ACTION_ICON.DELETE, + auth: ['infra:file:delete'], + onClick: handleDeleteBatch, + }, ]" /> diff --git a/apps/web-antd/src/views/infra/fileConfig/data.ts b/apps/web-antd/src/views/infra/fileConfig/data.ts index 11ea4475e..7126874f7 100644 --- a/apps/web-antd/src/views/infra/fileConfig/data.ts +++ b/apps/web-antd/src/views/infra/fileConfig/data.ts @@ -262,6 +262,7 @@ export function useGridFormSchema(): VbenFormSchema[] { /** 列表的字段 */ export function useGridColumns(): VxeTableGridOptions['columns'] { return [ + { type: 'checkbox', width: 40 }, { field: 'id', title: '编号', diff --git a/apps/web-antd/src/views/infra/fileConfig/index.vue b/apps/web-antd/src/views/infra/fileConfig/index.vue index 923387f6b..64dcd3ade 100644 --- a/apps/web-antd/src/views/infra/fileConfig/index.vue +++ b/apps/web-antd/src/views/infra/fileConfig/index.vue @@ -2,14 +2,17 @@ import type { VxeTableGridOptions } from '#/adapter/vxe-table'; import type { InfraFileConfigApi } from '#/api/infra/file-config'; +import { ref } from 'vue'; + import { confirm, Page, useVbenModal } from '@vben/common-ui'; -import { openWindow } from '@vben/utils'; +import { isEmpty, openWindow } from '@vben/utils'; import { message } from 'ant-design-vue'; import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; import { deleteFileConfig, + deleteFileConfigList, getFileConfigPage, testFileConfig, updateFileConfigMaster, @@ -97,6 +100,31 @@ async function handleDelete(row: InfraFileConfigApi.FileConfig) { } } +const checkedIds = ref([]); +function handleRowCheckboxChange({ + records, +}: { + records: InfraFileConfigApi.FileConfig[]; +}) { + checkedIds.value = records.map((item) => item.id as number); +} + +/** 批量删除文件配置 */ +async function handleDeleteBatch() { + const hideLoading = message.loading({ + content: $t('ui.actionMessage.deleting'), + duration: 0, + key: 'action_process_msg', + }); + try { + await deleteFileConfigList(checkedIds.value); + message.success($t('ui.actionMessage.deleteSuccess')); + onRefresh(); + } finally { + hideLoading(); + } +} + const [Grid, gridApi] = useVbenVxeGrid({ formOptions: { schema: useGridFormSchema(), @@ -118,12 +146,17 @@ const [Grid, gridApi] = useVbenVxeGrid({ }, rowConfig: { keyField: 'id', + isHover: true, }, toolbarConfig: { refresh: { code: 'query' }, search: true, }, } as VxeTableGridOptions, + gridEvents: { + checkboxAll: handleRowCheckboxChange, + checkboxChange: handleRowCheckboxChange, + }, }); @@ -141,6 +174,15 @@ const [Grid, gridApi] = useVbenVxeGrid({ auth: ['system:role:create'], onClick: handleCreate, }, + { + label: '批量删除', + type: 'primary', + danger: true, + disabled: isEmpty(checkedIds), + icon: ACTION_ICON.DELETE, + auth: ['infra:file-config:delete'], + onClick: handleDeleteBatch, + }, ]" /> diff --git a/apps/web-antd/src/views/infra/job/data.ts b/apps/web-antd/src/views/infra/job/data.ts index 982ee9f9b..0f1e663d7 100644 --- a/apps/web-antd/src/views/infra/job/data.ts +++ b/apps/web-antd/src/views/infra/job/data.ts @@ -129,6 +129,7 @@ export function useGridFormSchema(): VbenFormSchema[] { /** 表格列配置 */ export function useGridColumns(): VxeTableGridOptions['columns'] { return [ + { type: 'checkbox', width: 40 }, { field: 'id', title: '任务编号', diff --git a/apps/web-antd/src/views/infra/job/index.vue b/apps/web-antd/src/views/infra/job/index.vue index af06250de..8b8bbb71e 100644 --- a/apps/web-antd/src/views/infra/job/index.vue +++ b/apps/web-antd/src/views/infra/job/index.vue @@ -2,16 +2,18 @@ import type { VxeTableGridOptions } from '#/adapter/vxe-table'; import type { InfraJobApi } from '#/api/infra/job'; +import { ref } from 'vue'; import { useRouter } from 'vue-router'; import { confirm, Page, useVbenModal } from '@vben/common-ui'; -import { downloadFileFromBlobPart } from '@vben/utils'; +import { downloadFileFromBlobPart, isEmpty } from '@vben/utils'; import { message } from 'ant-design-vue'; import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; import { deleteJob, + deleteJobList, exportJob, getJobPage, runJob, @@ -115,6 +117,27 @@ async function handleDelete(row: InfraJobApi.Job) { } } +const checkedIds = ref([]); +function handleRowCheckboxChange({ records }: { records: InfraJobApi.Job[] }) { + checkedIds.value = records.map((item) => item.id as number); +} + +/** 批量删除任务 */ +async function handleDeleteBatch() { + const hideLoading = message.loading({ + content: $t('ui.actionMessage.deleting'), + duration: 0, + key: 'action_process_msg', + }); + try { + await deleteJobList(checkedIds.value); + message.success($t('ui.actionMessage.deleteSuccess')); + onRefresh(); + } finally { + hideLoading(); + } +} + const [Grid, gridApi] = useVbenVxeGrid({ formOptions: { schema: useGridFormSchema(), @@ -136,12 +159,17 @@ const [Grid, gridApi] = useVbenVxeGrid({ }, rowConfig: { keyField: 'id', + isHover: true, }, toolbarConfig: { refresh: { code: 'query' }, search: true, }, } as VxeTableGridOptions, + gridEvents: { + checkboxAll: handleRowCheckboxChange, + checkboxChange: handleRowCheckboxChange, + }, }); @@ -178,7 +206,16 @@ const [Grid, gridApi] = useVbenVxeGrid({ type: 'primary', icon: 'lucide:history', auth: ['infra:job:export'], - onClick: handleExport, + onClick: handleLog, + }, + { + label: '批量删除', + type: 'primary', + danger: true, + disabled: isEmpty(checkedIds), + icon: ACTION_ICON.DELETE, + auth: ['infra:job:delete'], + onClick: handleDeleteBatch, }, ]" /> From 0cc83967ed289f1e1e3b02c6d4d4703c38ee0b9f Mon Sep 17 00:00:00 2001 From: puhui999 Date: Sun, 15 Jun 2025 17:02:10 +0800 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20=E3=80=90antd=E3=80=91=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E6=89=B9=E9=87=8F=E5=88=A0=E9=99=A4=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web-antd/src/api/system/dept/index.ts | 5 + .../src/api/system/dict/data/index.ts | 7 + .../src/api/system/dict/type/index.ts | 7 + .../src/api/system/mail/account/index.ts | 7 + .../src/api/system/mail/template/index.ts | 7 + apps/web-antd/src/api/system/menu/index.ts | 5 + apps/web-antd/src/api/system/notice/index.ts | 7 + .../src/api/system/notify/template/index.ts | 7 + .../src/api/system/oauth2/token/index.ts | 7 + apps/web-antd/src/api/system/post/index.ts | 5 + apps/web-antd/src/api/system/role/index.ts | 5 + .../src/api/system/sms/channel/index.ts | 7 + .../src/api/system/sms/template/index.ts | 7 + .../src/api/system/tenant-package/index.ts | 7 + apps/web-antd/src/api/system/tenant/index.ts | 7 + apps/web-antd/src/api/system/user/index.ts | 5 + apps/web-antd/src/views/system/dept/data.ts | 1 + apps/web-antd/src/views/system/dept/index.vue | 65 +++- apps/web-antd/src/views/system/dict/data.ts | 2 + .../views/system/dict/modules/data-grid.vue | 52 +++- .../views/system/dict/modules/type-grid.vue | 51 +++- .../src/views/system/mail/account/data.ts | 1 + .../src/views/system/mail/account/index.vue | 53 +++- .../src/views/system/mail/template/data.ts | 1 + .../src/views/system/mail/template/index.vue | 54 +++- apps/web-antd/src/views/system/menu/data.ts | 1 + apps/web-antd/src/views/system/menu/index.vue | 102 ++++--- apps/web-antd/src/views/system/notice/data.ts | 1 + .../src/views/system/notice/index.vue | 64 +++- .../src/views/system/notify/template/data.ts | 1 + .../views/system/notify/template/index.vue | 52 +++- .../src/views/system/oauth2/token/data.ts | 1 + .../src/views/system/oauth2/token/index.vue | 64 ++++ apps/web-antd/src/views/system/post/data.ts | 1 + apps/web-antd/src/views/system/post/index.vue | 58 +++- apps/web-antd/src/views/system/role/data.ts | 1 + apps/web-antd/src/views/system/role/index.vue | 114 ++++--- .../src/views/system/sms/template/data.ts | 1 + .../src/views/system/sms/template/index.vue | 52 +++- apps/web-antd/src/views/system/tenant/data.ts | 1 + .../src/views/system/tenant/index.vue | 56 +++- .../src/views/system/tenantPackage/data.ts | 1 + .../src/views/system/tenantPackage/index.vue | 51 +++- apps/web-antd/src/views/system/user/data.ts | 1 + apps/web-antd/src/views/system/user/index.vue | 289 +++++++++--------- 45 files changed, 997 insertions(+), 297 deletions(-) diff --git a/apps/web-antd/src/api/system/dept/index.ts b/apps/web-antd/src/api/system/dept/index.ts index d2677a793..d6403d72a 100644 --- a/apps/web-antd/src/api/system/dept/index.ts +++ b/apps/web-antd/src/api/system/dept/index.ts @@ -45,3 +45,8 @@ export async function updateDept(data: SystemDeptApi.Dept) { export async function deleteDept(id: number) { return requestClient.delete(`/system/dept/delete?id=${id}`); } + +/** 批量删除部门 */ +export async function deleteDeptList(ids: number[]) { + return requestClient.delete(`/system/dept/delete-list?ids=${ids.join(',')}`); +} diff --git a/apps/web-antd/src/api/system/dict/data/index.ts b/apps/web-antd/src/api/system/dict/data/index.ts index a64330cda..6bf7473ce 100644 --- a/apps/web-antd/src/api/system/dict/data/index.ts +++ b/apps/web-antd/src/api/system/dict/data/index.ts @@ -48,6 +48,13 @@ export function deleteDictData(id: number) { return requestClient.delete(`/system/dict-data/delete?id=${id}`); } +// 批量删除字典数据 +export function deleteDictDataList(ids: number[]) { + return requestClient.delete( + `/system/dict-data/delete-list?ids=${ids.join(',')}`, + ); +} + // 导出字典类型数据 export function exportDictData(params: any) { return requestClient.download('/system/dict-data/export', { params }); diff --git a/apps/web-antd/src/api/system/dict/type/index.ts b/apps/web-antd/src/api/system/dict/type/index.ts index 612fe1052..8c2951cc1 100644 --- a/apps/web-antd/src/api/system/dict/type/index.ts +++ b/apps/web-antd/src/api/system/dict/type/index.ts @@ -42,6 +42,13 @@ export function deleteDictType(id: number) { return requestClient.delete(`/system/dict-type/delete?id=${id}`); } +// 批量删除字典 +export function deleteDictTypeList(ids: number[]) { + return requestClient.delete( + `/system/dict-type/delete-list?ids=${ids.join(',')}`, + ); +} + // 导出字典类型 export function exportDictType(params: any) { return requestClient.download('/system/dict-type/export', { params }); diff --git a/apps/web-antd/src/api/system/mail/account/index.ts b/apps/web-antd/src/api/system/mail/account/index.ts index 8a43a3326..7f506fd87 100644 --- a/apps/web-antd/src/api/system/mail/account/index.ts +++ b/apps/web-antd/src/api/system/mail/account/index.ts @@ -49,6 +49,13 @@ export function deleteMailAccount(id: number) { return requestClient.delete(`/system/mail-account/delete?id=${id}`); } +/** 批量删除邮箱账号 */ +export function deleteMailAccountList(ids: number[]) { + return requestClient.delete( + `/system/mail-account/delete-list?ids=${ids.join(',')}`, + ); +} + /** 获得邮箱账号精简列表 */ export function getSimpleMailAccountList() { return requestClient.get( diff --git a/apps/web-antd/src/api/system/mail/template/index.ts b/apps/web-antd/src/api/system/mail/template/index.ts index 34b4a09d0..3282afa56 100644 --- a/apps/web-antd/src/api/system/mail/template/index.ts +++ b/apps/web-antd/src/api/system/mail/template/index.ts @@ -56,6 +56,13 @@ export function deleteMailTemplate(id: number) { return requestClient.delete(`/system/mail-template/delete?id=${id}`); } +/** 批量删除邮件模板 */ +export function deleteMailTemplateList(ids: number[]) { + return requestClient.delete( + `/system/mail-template/delete-list?ids=${ids.join(',')}`, + ); +} + /** 发送邮件 */ export function sendMail(data: SystemMailTemplateApi.MailSendReqVO) { return requestClient.post('/system/mail-template/send-mail', data); diff --git a/apps/web-antd/src/api/system/menu/index.ts b/apps/web-antd/src/api/system/menu/index.ts index 5d23e5230..b296d815b 100644 --- a/apps/web-antd/src/api/system/menu/index.ts +++ b/apps/web-antd/src/api/system/menu/index.ts @@ -52,3 +52,8 @@ export async function updateMenu(data: SystemMenuApi.Menu) { export async function deleteMenu(id: number) { return requestClient.delete(`/system/menu/delete?id=${id}`); } + +/** 批量删除菜单 */ +export async function deleteMenuList(ids: number[]) { + return requestClient.delete(`/system/menu/delete-list?ids=${ids.join(',')}`); +} diff --git a/apps/web-antd/src/api/system/notice/index.ts b/apps/web-antd/src/api/system/notice/index.ts index dac9ec708..5ae888538 100644 --- a/apps/web-antd/src/api/system/notice/index.ts +++ b/apps/web-antd/src/api/system/notice/index.ts @@ -46,6 +46,13 @@ export function deleteNotice(id: number) { return requestClient.delete(`/system/notice/delete?id=${id}`); } +/** 批量删除公告 */ +export function deleteNoticeList(ids: number[]) { + return requestClient.delete( + `/system/notice/delete-list?ids=${ids.join(',')}`, + ); +} + /** 推送公告 */ export function pushNotice(id: number) { return requestClient.post(`/system/notice/push?id=${id}`); diff --git a/apps/web-antd/src/api/system/notify/template/index.ts b/apps/web-antd/src/api/system/notify/template/index.ts index 5f2e3de29..dd19f4b8f 100644 --- a/apps/web-antd/src/api/system/notify/template/index.ts +++ b/apps/web-antd/src/api/system/notify/template/index.ts @@ -59,6 +59,13 @@ export function deleteNotifyTemplate(id: number) { return requestClient.delete(`/system/notify-template/delete?id=${id}`); } +/** 批量删除站内信模板 */ +export function deleteNotifyTemplateList(ids: number[]) { + return requestClient.delete( + `/system/notify-template/delete-list?ids=${ids.join(',')}`, + ); +} + /** 导出站内信模板 */ export function exportNotifyTemplate(params: any) { return requestClient.download('/system/notify-template/export-excel', { diff --git a/apps/web-antd/src/api/system/oauth2/token/index.ts b/apps/web-antd/src/api/system/oauth2/token/index.ts index bd3697915..9209fd713 100644 --- a/apps/web-antd/src/api/system/oauth2/token/index.ts +++ b/apps/web-antd/src/api/system/oauth2/token/index.ts @@ -32,3 +32,10 @@ export function deleteOAuth2Token(accessToken: string) { `/system/oauth2-token/delete?accessToken=${accessToken}`, ); } + +/** 批量删除 OAuth2.0 令牌 */ +export function deleteOAuth2TokenList(accessTokens: string[]) { + return requestClient.delete( + `/system/oauth2-token/delete-list?accessTokens=${accessTokens.join(',')}`, + ); +} diff --git a/apps/web-antd/src/api/system/post/index.ts b/apps/web-antd/src/api/system/post/index.ts index a82f58155..06df146c3 100644 --- a/apps/web-antd/src/api/system/post/index.ts +++ b/apps/web-antd/src/api/system/post/index.ts @@ -50,6 +50,11 @@ export function deletePost(id: number) { return requestClient.delete(`/system/post/delete?id=${id}`); } +/** 批量删除岗位 */ +export function deletePostList(ids: number[]) { + return requestClient.delete(`/system/post/delete-list?ids=${ids.join(',')}`); +} + /** 导出岗位 */ export function exportPost(params: any) { return requestClient.download('/system/post/export', { diff --git a/apps/web-antd/src/api/system/role/index.ts b/apps/web-antd/src/api/system/role/index.ts index 07824c43e..23d5ade98 100644 --- a/apps/web-antd/src/api/system/role/index.ts +++ b/apps/web-antd/src/api/system/role/index.ts @@ -50,6 +50,11 @@ export function deleteRole(id: number) { return requestClient.delete(`/system/role/delete?id=${id}`); } +/** 批量删除角色 */ +export function deleteRoleList(ids: number[]) { + return requestClient.delete(`/system/role/delete-list?ids=${ids.join(',')}`); +} + /** 导出角色 */ export function exportRole(params: any) { return requestClient.download('/system/role/export-excel', { diff --git a/apps/web-antd/src/api/system/sms/channel/index.ts b/apps/web-antd/src/api/system/sms/channel/index.ts index 56890bea5..575c92447 100644 --- a/apps/web-antd/src/api/system/sms/channel/index.ts +++ b/apps/web-antd/src/api/system/sms/channel/index.ts @@ -54,6 +54,13 @@ export function deleteSmsChannel(id: number) { return requestClient.delete(`/system/sms-channel/delete?id=${id}`); } +/** 批量删除短信渠道 */ +export function deleteSmsChannelList(ids: number[]) { + return requestClient.delete( + `/system/sms-channel/delete-list?ids=${ids.join(',')}`, + ); +} + /** 导出短信渠道 */ export function exportSmsChannel(params: any) { return requestClient.download('/system/sms-channel/export', { params }); diff --git a/apps/web-antd/src/api/system/sms/template/index.ts b/apps/web-antd/src/api/system/sms/template/index.ts index 63660bdf9..eccfb911e 100644 --- a/apps/web-antd/src/api/system/sms/template/index.ts +++ b/apps/web-antd/src/api/system/sms/template/index.ts @@ -57,6 +57,13 @@ export function deleteSmsTemplate(id: number) { return requestClient.delete(`/system/sms-template/delete?id=${id}`); } +/** 批量删除短信模板 */ +export function deleteSmsTemplateList(ids: number[]) { + return requestClient.delete( + `/system/sms-template/delete-list?ids=${ids.join(',')}`, + ); +} + /** 导出短信模板 */ export function exportSmsTemplate(params: any) { return requestClient.download('/system/sms-template/export-excel', { diff --git a/apps/web-antd/src/api/system/tenant-package/index.ts b/apps/web-antd/src/api/system/tenant-package/index.ts index 5066cea98..53be78f73 100644 --- a/apps/web-antd/src/api/system/tenant-package/index.ts +++ b/apps/web-antd/src/api/system/tenant-package/index.ts @@ -49,6 +49,13 @@ export function deleteTenantPackage(id: number) { return requestClient.delete(`/system/tenant-package/delete?id=${id}`); } +/** 批量删除租户套餐 */ +export function deleteTenantPackageList(ids: number[]) { + return requestClient.delete( + `/system/tenant-package/delete-list?ids=${ids.join(',')}`, + ); +} + /** 获取租户套餐精简信息列表 */ export function getTenantPackageList() { return requestClient.get( diff --git a/apps/web-antd/src/api/system/tenant/index.ts b/apps/web-antd/src/api/system/tenant/index.ts index 3bed9249c..c18a4dfab 100644 --- a/apps/web-antd/src/api/system/tenant/index.ts +++ b/apps/web-antd/src/api/system/tenant/index.ts @@ -61,6 +61,13 @@ export function deleteTenant(id: number) { return requestClient.delete(`/system/tenant/delete?id=${id}`); } +/** 批量删除租户 */ +export function deleteTenantList(ids: number[]) { + return requestClient.delete( + `/system/tenant/delete-list?ids=${ids.join(',')}`, + ); +} + /** 导出租户 */ export function exportTenant(params: any) { return requestClient.download('/system/tenant/export-excel', { diff --git a/apps/web-antd/src/api/system/user/index.ts b/apps/web-antd/src/api/system/user/index.ts index 52d8cdd2e..1f51a5bc7 100644 --- a/apps/web-antd/src/api/system/user/index.ts +++ b/apps/web-antd/src/api/system/user/index.ts @@ -49,6 +49,11 @@ export function deleteUser(id: number) { return requestClient.delete(`/system/user/delete?id=${id}`); } +/** 批量删除用户 */ +export function deleteUserList(ids: number[]) { + return requestClient.delete(`/system/user/delete-list?ids=${ids.join(',')}`); +} + /** 导出用户 */ export function exportUser(params: any) { return requestClient.download('/system/user/export', params); diff --git a/apps/web-antd/src/views/system/dept/data.ts b/apps/web-antd/src/views/system/dept/data.ts index 155f60f21..0da23687b 100644 --- a/apps/web-antd/src/views/system/dept/data.ts +++ b/apps/web-antd/src/views/system/dept/data.ts @@ -113,6 +113,7 @@ export function useGridColumns( getLeaderName?: (userId: number) => string | undefined, ): VxeTableGridOptions['columns'] { return [ + { type: 'checkbox', width: 40 }, { field: 'name', title: '部门名称', diff --git a/apps/web-antd/src/views/system/dept/index.vue b/apps/web-antd/src/views/system/dept/index.vue index f62e6db7a..f8d875af9 100644 --- a/apps/web-antd/src/views/system/dept/index.vue +++ b/apps/web-antd/src/views/system/dept/index.vue @@ -6,11 +6,12 @@ import type { SystemUserApi } from '#/api/system/user'; import { onMounted, ref } from 'vue'; import { Page, useVbenModal } from '@vben/common-ui'; +import { isEmpty } from '@vben/utils'; import { message } from 'ant-design-vue'; import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; -import { deleteDept, getDeptList } from '#/api/system/dept'; +import { deleteDept, deleteDeptList, getDeptList } from '#/api/system/dept'; import { getSimpleUserList } from '#/api/system/user'; import { $t } from '#/locales'; @@ -60,14 +61,37 @@ function handleEdit(row: SystemDeptApi.Dept) { async function handleDelete(row: SystemDeptApi.Dept) { const hideLoading = message.loading({ content: $t('ui.actionMessage.deleting', [row.name]), - key: 'action_key_msg', + duration: 0, + key: 'action_process_msg', }); try { await deleteDept(row.id as number); - message.success({ - content: $t('ui.actionMessage.deleteSuccess', [row.name]), - key: 'action_key_msg', - }); + message.success($t('ui.actionMessage.deleteSuccess', [row.name])); + onRefresh(); + } finally { + hideLoading(); + } +} + +const checkedIds = ref([]); +function handleRowCheckboxChange({ + records, +}: { + records: SystemDeptApi.Dept[]; +}) { + checkedIds.value = records.map((item) => item.id as number); +} + +/** 批量删除部门 */ +async function handleDeleteBatch() { + const hideLoading = message.loading({ + content: $t('ui.actionMessage.deleting'), + duration: 0, + key: 'action_process_msg', + }); + try { + await deleteDeptList(checkedIds.value); + message.success($t('ui.actionMessage.deleteSuccess')); onRefresh(); } finally { hideLoading(); @@ -78,31 +102,33 @@ const [Grid, gridApi] = useVbenVxeGrid({ gridOptions: { columns: useGridColumns(getLeaderName), height: 'auto', - keepSource: true, - pagerConfig: { - enabled: false, - }, proxyConfig: { ajax: { - query: async (_params) => { + query: async () => { return await getDeptList(); }, }, }, rowConfig: { keyField: 'id', + isHover: true, }, toolbarConfig: { refresh: { code: 'query' }, + search: true, }, treeConfig: { - parentField: 'parentId', - rowField: 'id', transform: true, + rowField: 'id', + parentField: 'parentId', expandAll: true, - reserve: true, + accordion: false, }, - } as VxeTableGridOptions, + } as VxeTableGridOptions, + gridEvents: { + checkboxAll: handleRowCheckboxChange, + checkboxChange: handleRowCheckboxChange, + }, }); /** 初始化 */ @@ -130,6 +156,15 @@ onMounted(async () => { type: 'primary', onClick: toggleExpand, }, + { + label: '批量删除', + type: 'primary', + danger: true, + disabled: isEmpty(checkedIds), + icon: ACTION_ICON.DELETE, + auth: ['system:dept:delete'], + onClick: handleDeleteBatch, + }, ]" /> diff --git a/apps/web-antd/src/views/system/dict/data.ts b/apps/web-antd/src/views/system/dict/data.ts index 28586f169..f1d46c2f8 100644 --- a/apps/web-antd/src/views/system/dict/data.ts +++ b/apps/web-antd/src/views/system/dict/data.ts @@ -101,6 +101,7 @@ export function useTypeGridFormSchema(): VbenFormSchema[] { /** 类型列表的字段 */ export function useTypeGridColumns(): VxeTableGridOptions['columns'] { return [ + { type: 'checkbox', width: 40 }, { field: 'id', title: '字典编号', @@ -288,6 +289,7 @@ export function useDataGridFormSchema(): VbenFormSchema[] { */ export function useDataGridColumns(): VxeTableGridOptions['columns'] { return [ + { type: 'checkbox', width: 40 }, { field: 'id', title: '字典编码', diff --git a/apps/web-antd/src/views/system/dict/modules/data-grid.vue b/apps/web-antd/src/views/system/dict/modules/data-grid.vue index 22d4d5cc7..d94351ff4 100644 --- a/apps/web-antd/src/views/system/dict/modules/data-grid.vue +++ b/apps/web-antd/src/views/system/dict/modules/data-grid.vue @@ -2,16 +2,17 @@ import type { VxeTableGridOptions } from '#/adapter/vxe-table'; import type { SystemDictDataApi } from '#/api/system/dict/data'; -import { watch } from 'vue'; +import { ref, watch } from 'vue'; import { useVbenModal } from '@vben/common-ui'; -import { downloadFileFromBlobPart } from '@vben/utils'; +import { downloadFileFromBlobPart, isEmpty } from '@vben/utils'; import { message } from 'ant-design-vue'; import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; import { deleteDictData, + deleteDictDataList, exportDictData, getDictDataPage, } from '#/api/system/dict/data'; @@ -57,14 +58,37 @@ function handleEdit(row: SystemDictDataApi.DictData) { async function handleDelete(row: SystemDictDataApi.DictData) { const hideLoading = message.loading({ content: $t('ui.actionMessage.deleting', [row.label]), - key: 'action_key_msg', + duration: 0, + key: 'action_process_msg', }); try { await deleteDictData(row.id as number); - message.success({ - content: $t('ui.actionMessage.deleteSuccess', [row.label]), - key: 'action_key_msg', - }); + message.success($t('ui.actionMessage.deleteSuccess', [row.label])); + onRefresh(); + } finally { + hideLoading(); + } +} + +const checkedIds = ref([]); +function handleRowCheckboxChange({ + records, +}: { + records: SystemDictDataApi.DictData[]; +}) { + checkedIds.value = records.map((item) => item.id as number); +} + +/** 批量删除字典数据 */ +async function handleDeleteBatch() { + const hideLoading = message.loading({ + content: $t('ui.actionMessage.deleting'), + duration: 0, + key: 'action_process_msg', + }); + try { + await deleteDictDataList(checkedIds.value); + message.success($t('ui.actionMessage.deleteSuccess')); onRefresh(); } finally { hideLoading(); @@ -93,12 +117,17 @@ const [Grid, gridApi] = useVbenVxeGrid({ }, rowConfig: { keyField: 'id', + isHover: true, }, toolbarConfig: { refresh: { code: 'query' }, search: true, }, } as VxeTableGridOptions, + gridEvents: { + checkboxAll: handleRowCheckboxChange, + checkboxChange: handleRowCheckboxChange, + }, }); /** 监听 dictType 变化,重新查询 */ @@ -134,6 +163,15 @@ watch( auth: ['system:dict:export'], onClick: handleExport, }, + { + label: '批量删除', + type: 'primary', + danger: true, + disabled: isEmpty(checkedIds), + icon: ACTION_ICON.DELETE, + auth: ['system:dict:delete'], + onClick: handleDeleteBatch, + }, ]" /> diff --git a/apps/web-antd/src/views/system/dict/modules/type-grid.vue b/apps/web-antd/src/views/system/dict/modules/type-grid.vue index 0caa4afc5..2c6fce228 100644 --- a/apps/web-antd/src/views/system/dict/modules/type-grid.vue +++ b/apps/web-antd/src/views/system/dict/modules/type-grid.vue @@ -5,14 +5,17 @@ import type { } from '#/adapter/vxe-table'; import type { SystemDictTypeApi } from '#/api/system/dict/type'; +import { ref } from 'vue'; + import { useVbenModal } from '@vben/common-ui'; -import { downloadFileFromBlobPart } from '@vben/utils'; +import { downloadFileFromBlobPart, isEmpty } from '@vben/utils'; import { message } from 'ant-design-vue'; import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; import { deleteDictType, + deleteDictTypeList, exportDictType, getDictTypePage, } from '#/api/system/dict/type'; @@ -53,14 +56,37 @@ function handleEdit(row: any) { async function handleDelete(row: SystemDictTypeApi.DictType) { const hideLoading = message.loading({ content: $t('ui.actionMessage.deleting', [row.name]), - key: 'action_key_msg', + duration: 0, + key: 'action_process_msg', }); try { await deleteDictType(row.id as number); - message.success({ - content: $t('ui.actionMessage.deleteSuccess', [row.name]), - key: 'action_key_msg', - }); + message.success($t('ui.actionMessage.deleteSuccess', [row.name])); + onRefresh(); + } finally { + hideLoading(); + } +} + +const checkedIds = ref([]); +function handleRowCheckboxChange({ + records, +}: { + records: SystemDictTypeApi.DictType[]; +}) { + checkedIds.value = records.map((item) => item.id as number); +} + +/** 批量删除字典类型 */ +async function handleDeleteBatch() { + const hideLoading = message.loading({ + content: $t('ui.actionMessage.deleting'), + duration: 0, + key: 'action_process_msg', + }); + try { + await deleteDictTypeList(checkedIds.value); + message.success($t('ui.actionMessage.deleteSuccess')); onRefresh(); } finally { hideLoading(); @@ -72,6 +98,8 @@ const gridEvents: VxeGridListeners = { cellClick: ({ row }) => { emit('select', row.type); }, + checkboxAll: handleRowCheckboxChange, + checkboxChange: handleRowCheckboxChange, }; const [Grid, gridApi] = useVbenVxeGrid({ @@ -81,7 +109,6 @@ const [Grid, gridApi] = useVbenVxeGrid({ gridOptions: { columns: useTypeGridColumns(), height: 'auto', - keepSource: true, proxyConfig: { ajax: { query: async ({ page }, formValues) => { @@ -96,6 +123,7 @@ const [Grid, gridApi] = useVbenVxeGrid({ rowConfig: { keyField: 'id', isCurrent: true, + isHover: true, }, toolbarConfig: { refresh: { code: 'query' }, @@ -128,6 +156,15 @@ const [Grid, gridApi] = useVbenVxeGrid({ auth: ['system:dict:export'], onClick: handleExport, }, + { + label: '批量删除', + type: 'primary', + danger: true, + disabled: isEmpty(checkedIds), + icon: ACTION_ICON.DELETE, + auth: ['system:dict:delete'], + onClick: handleDeleteBatch, + }, ]" /> diff --git a/apps/web-antd/src/views/system/mail/account/data.ts b/apps/web-antd/src/views/system/mail/account/data.ts index e4cbbec40..dfe9775a5 100644 --- a/apps/web-antd/src/views/system/mail/account/data.ts +++ b/apps/web-antd/src/views/system/mail/account/data.ts @@ -122,6 +122,7 @@ export function useGridFormSchema(): VbenFormSchema[] { /** 列表的字段 */ export function useGridColumns(): VxeTableGridOptions['columns'] { return [ + { type: 'checkbox', width: 40 }, { field: 'id', title: '编号', diff --git a/apps/web-antd/src/views/system/mail/account/index.vue b/apps/web-antd/src/views/system/mail/account/index.vue index c67a4d0a6..3da0308b9 100644 --- a/apps/web-antd/src/views/system/mail/account/index.vue +++ b/apps/web-antd/src/views/system/mail/account/index.vue @@ -2,13 +2,17 @@ import type { VxeTableGridOptions } from '#/adapter/vxe-table'; import type { SystemMailAccountApi } from '#/api/system/mail/account'; +import { ref } from 'vue'; + import { DocAlert, Page, useVbenModal } from '@vben/common-ui'; +import { isEmpty } from '@vben/utils'; import { message } from 'ant-design-vue'; import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; import { deleteMailAccount, + deleteMailAccountList, getMailAccountPage, } from '#/api/system/mail/account'; import { $t } from '#/locales'; @@ -40,14 +44,37 @@ function handleEdit(row: SystemMailAccountApi.MailAccount) { async function handleDelete(row: SystemMailAccountApi.MailAccount) { const hideLoading = message.loading({ content: $t('ui.actionMessage.deleting', [row.mail]), - key: 'action_key_msg', + duration: 0, + key: 'action_process_msg', }); try { await deleteMailAccount(row.id as number); - message.success({ - content: $t('ui.actionMessage.deleteSuccess', [row.mail]), - key: 'action_key_msg', - }); + message.success($t('ui.actionMessage.deleteSuccess', [row.mail])); + onRefresh(); + } finally { + hideLoading(); + } +} + +const checkedIds = ref([]); +function handleRowCheckboxChange({ + records, +}: { + records: SystemMailAccountApi.MailAccount[]; +}) { + checkedIds.value = records.map((item) => item.id as number); +} + +/** 批量删除邮箱账号 */ +async function handleDeleteBatch() { + const hideLoading = message.loading({ + content: $t('ui.actionMessage.deleting'), + duration: 0, + key: 'action_process_msg', + }); + try { + await deleteMailAccountList(checkedIds.value); + message.success($t('ui.actionMessage.deleteSuccess')); onRefresh(); } finally { hideLoading(); @@ -75,12 +102,17 @@ const [Grid, gridApi] = useVbenVxeGrid({ }, rowConfig: { keyField: 'id', + isHover: true, }, toolbarConfig: { refresh: { code: 'query' }, search: true, }, } as VxeTableGridOptions, + gridEvents: { + checkboxAll: handleRowCheckboxChange, + checkboxChange: handleRowCheckboxChange, + }, }); @@ -121,7 +162,7 @@ const [Grid, gridApi] = useVbenVxeGrid({ icon: ACTION_ICON.DELETE, auth: ['system:mail-account:delete'], popConfirm: { - title: $t('ui.actionMessage.deleteConfirm', [row.name]), + title: $t('ui.actionMessage.deleteConfirm', [row.mail]), confirm: handleDelete.bind(null, row), }, }, diff --git a/apps/web-antd/src/views/system/mail/template/data.ts b/apps/web-antd/src/views/system/mail/template/data.ts index 06f03457a..7b46a9e60 100644 --- a/apps/web-antd/src/views/system/mail/template/data.ts +++ b/apps/web-antd/src/views/system/mail/template/data.ts @@ -192,6 +192,7 @@ export function useGridColumns( getAccountMail?: (accountId: number) => string | undefined, ): VxeTableGridOptions['columns'] { return [ + { type: 'checkbox', width: 40 }, { field: 'id', title: '编号', diff --git a/apps/web-antd/src/views/system/mail/template/index.vue b/apps/web-antd/src/views/system/mail/template/index.vue index 35a894ef0..b0bf5fcce 100644 --- a/apps/web-antd/src/views/system/mail/template/index.vue +++ b/apps/web-antd/src/views/system/mail/template/index.vue @@ -6,6 +6,7 @@ import type { SystemMailTemplateApi } from '#/api/system/mail/template'; import { onMounted, ref } from 'vue'; import { DocAlert, Page, useVbenModal } from '@vben/common-ui'; +import { isEmpty } from '@vben/utils'; import { message } from 'ant-design-vue'; @@ -13,6 +14,7 @@ import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; import { getSimpleMailAccountList } from '#/api/system/mail/account'; import { deleteMailTemplate, + deleteMailTemplateList, getMailTemplatePage, } from '#/api/system/mail/template'; import { $t } from '#/locales'; @@ -55,17 +57,43 @@ function handleSend(row: SystemMailTemplateApi.MailTemplate) { /** 删除邮件模板 */ async function handleDelete(row: SystemMailTemplateApi.MailTemplate) { - message.loading({ + const hideLoading = message.loading({ content: $t('ui.actionMessage.deleting', [row.name]), duration: 0, key: 'action_process_msg', }); - await deleteMailTemplate(row.id as number); - message.success({ - content: $t('ui.actionMessage.deleteSuccess', [row.name]), - key: 'action_key_msg', + try { + await deleteMailTemplate(row.id as number); + message.success($t('ui.actionMessage.deleteSuccess', [row.name])); + onRefresh(); + } finally { + hideLoading(); + } +} + +const checkedIds = ref([]); +function handleRowCheckboxChange({ + records, +}: { + records: SystemMailTemplateApi.MailTemplate[]; +}) { + checkedIds.value = records.map((item) => item.id as number); +} + +/** 批量删除邮件模板 */ +async function handleDeleteBatch() { + const hideLoading = message.loading({ + content: $t('ui.actionMessage.deleting'), + duration: 0, + key: 'action_process_msg', }); - onRefresh(); + try { + await deleteMailTemplateList(checkedIds.value); + message.success($t('ui.actionMessage.deleteSuccess')); + onRefresh(); + } finally { + hideLoading(); + } } /** 获取邮箱账号 */ @@ -94,12 +122,17 @@ const [Grid, gridApi] = useVbenVxeGrid({ }, rowConfig: { keyField: 'id', + isHover: true, }, toolbarConfig: { refresh: { code: 'query' }, search: true, }, } as VxeTableGridOptions, + gridEvents: { + checkboxAll: handleRowCheckboxChange, + checkboxChange: handleRowCheckboxChange, + }, }); /** 初始化 */ @@ -126,6 +159,15 @@ onMounted(async () => { auth: ['system:mail-template:create'], onClick: handleCreate, }, + { + label: '批量删除', + type: 'primary', + danger: true, + disabled: isEmpty(checkedIds), + icon: ACTION_ICON.DELETE, + auth: ['system:mail-template:delete'], + onClick: handleDeleteBatch, + }, ]" /> diff --git a/apps/web-antd/src/views/system/menu/data.ts b/apps/web-antd/src/views/system/menu/data.ts index 0cc5a6a86..0c9c49f2e 100644 --- a/apps/web-antd/src/views/system/menu/data.ts +++ b/apps/web-antd/src/views/system/menu/data.ts @@ -268,6 +268,7 @@ export function useFormSchema(): VbenFormSchema[] { /** 列表的字段 */ export function useGridColumns(): VxeTableGridOptions['columns'] { return [ + { type: 'checkbox', width: 40 }, { field: 'name', title: '菜单名称', diff --git a/apps/web-antd/src/views/system/menu/index.vue b/apps/web-antd/src/views/system/menu/index.vue index 9519bb277..cbf432907 100644 --- a/apps/web-antd/src/views/system/menu/index.vue +++ b/apps/web-antd/src/views/system/menu/index.vue @@ -6,11 +6,12 @@ import { ref } from 'vue'; import { DocAlert, Page, useVbenModal } from '@vben/common-ui'; import { IconifyIcon } from '@vben/icons'; +import { isEmpty } from '@vben/utils'; import { message } from 'ant-design-vue'; import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; -import { deleteMenu, getMenuList } from '#/api/system/menu'; +import { deleteMenu, deleteMenuList, getMenuList } from '#/api/system/menu'; import { $t } from '#/locales'; import { SystemMenuTypeEnum } from '#/utils'; @@ -28,13 +29,8 @@ function onRefresh() { } /** 创建菜单 */ -function handleCreate() { - formModalApi.setData({}).open(); -} - -/** 添加下级菜单 */ -function handleAppend(row: SystemMenuApi.Menu) { - formModalApi.setData({ pid: row.id }).open(); +function handleCreate(parentId?: number) { + formModalApi.setData({ parentId: parentId || 0 }).open(); } /** 编辑菜单 */ @@ -46,55 +42,74 @@ function handleEdit(row: SystemMenuApi.Menu) { async function handleDelete(row: SystemMenuApi.Menu) { const hideLoading = message.loading({ content: $t('ui.actionMessage.deleting', [row.name]), - key: 'action_key_msg', + duration: 0, + key: 'action_process_msg', }); try { - await deleteMenu(row.id as number); - message.success({ - content: $t('ui.actionMessage.deleteSuccess', [row.name]), - key: 'action_key_msg', - }); + await deleteMenu(row.id); + message.success($t('ui.actionMessage.deleteSuccess', [row.name])); onRefresh(); } finally { hideLoading(); } } -/** 切换树形展开/收缩状态 */ -const isExpanded = ref(false); -function toggleExpand() { - isExpanded.value = !isExpanded.value; - gridApi.grid.setAllTreeExpand(isExpanded.value); +const checkedIds = ref([]); +function handleRowCheckboxChange({ + records, +}: { + records: SystemMenuApi.Menu[]; +}) { + checkedIds.value = records.map((item) => item.id); +} + +/** 批量删除菜单 */ +async function handleDeleteBatch() { + const hideLoading = message.loading({ + content: $t('ui.actionMessage.deleting'), + duration: 0, + key: 'action_process_msg', + }); + try { + await deleteMenuList(checkedIds.value); + message.success($t('ui.actionMessage.deleteSuccess')); + onRefresh(); + } finally { + hideLoading(); + } } const [Grid, gridApi] = useVbenVxeGrid({ gridOptions: { columns: useGridColumns(), height: 'auto', - keepSource: true, - pagerConfig: { - enabled: false, - }, proxyConfig: { ajax: { - query: async (_params) => { + query: async () => { return await getMenuList(); }, }, }, + treeConfig: { + transform: true, + rowField: 'id', + parentField: 'parentId', + expandAll: true, + accordion: false, + }, rowConfig: { keyField: 'id', + isHover: true, }, toolbarConfig: { refresh: { code: 'query' }, + search: true, }, - treeConfig: { - parentField: 'parentId', - rowField: 'id', - transform: true, - reserve: true, - }, - } as VxeTableGridOptions, + } as VxeTableGridOptions, + gridEvents: { + checkboxAll: handleRowCheckboxChange, + checkboxChange: handleRowCheckboxChange, + }, }); @@ -109,7 +124,7 @@ const [Grid, gridApi] = useVbenVxeGrid({ - + @@ -139,7 +181,7 @@ const [Grid, gridApi] = useVbenVxeGrid({ icon: ACTION_ICON.DELETE, auth: ['system:notice:delete'], popConfirm: { - title: $t('ui.actionMessage.deleteConfirm', [row.name]), + title: $t('ui.actionMessage.deleteConfirm', [row.title]), confirm: handleDelete.bind(null, row), }, }, diff --git a/apps/web-antd/src/views/system/notify/template/data.ts b/apps/web-antd/src/views/system/notify/template/data.ts index fd0a63f09..1a828b3b8 100644 --- a/apps/web-antd/src/views/system/notify/template/data.ts +++ b/apps/web-antd/src/views/system/notify/template/data.ts @@ -226,6 +226,7 @@ export function useSendNotifyFormSchema(): VbenFormSchema[] { /** 列表的字段 */ export function useGridColumns(): VxeTableGridOptions['columns'] { return [ + { type: 'checkbox', width: 40 }, { field: 'id', title: '编号', diff --git a/apps/web-antd/src/views/system/notify/template/index.vue b/apps/web-antd/src/views/system/notify/template/index.vue index bdd1f409e..2ef4b864f 100644 --- a/apps/web-antd/src/views/system/notify/template/index.vue +++ b/apps/web-antd/src/views/system/notify/template/index.vue @@ -2,14 +2,17 @@ import type { VxeTableGridOptions } from '#/adapter/vxe-table'; import type { SystemNotifyTemplateApi } from '#/api/system/notify/template'; +import { ref } from 'vue'; + import { DocAlert, Page, useVbenModal } from '@vben/common-ui'; -import { downloadFileFromBlobPart } from '@vben/utils'; +import { downloadFileFromBlobPart, isEmpty } from '@vben/utils'; import { message } from 'ant-design-vue'; import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; import { deleteNotifyTemplate, + deleteNotifyTemplateList, exportNotifyTemplate, getNotifyTemplatePage, } from '#/api/system/notify/template'; @@ -59,14 +62,37 @@ function handleSend(row: SystemNotifyTemplateApi.NotifyTemplate) { async function handleDelete(row: SystemNotifyTemplateApi.NotifyTemplate) { const hideLoading = message.loading({ content: $t('ui.actionMessage.deleting', [row.name]), - key: 'action_key_msg', + duration: 0, + key: 'action_process_msg', }); try { await deleteNotifyTemplate(row.id as number); - message.success({ - content: $t('ui.actionMessage.deleteSuccess', [row.name]), - key: 'action_key_msg', - }); + message.success($t('ui.actionMessage.deleteSuccess', [row.name])); + onRefresh(); + } finally { + hideLoading(); + } +} + +const checkedIds = ref([]); +function handleRowCheckboxChange({ + records, +}: { + records: SystemNotifyTemplateApi.NotifyTemplate[]; +}) { + checkedIds.value = records.map((item) => item.id as number); +} + +/** 批量删除站内信模板 */ +async function handleDeleteBatch() { + const hideLoading = message.loading({ + content: $t('ui.actionMessage.deleting'), + duration: 0, + key: 'action_process_msg', + }); + try { + await deleteNotifyTemplateList(checkedIds.value); + message.success($t('ui.actionMessage.deleteSuccess')); onRefresh(); } finally { hideLoading(); @@ -94,12 +120,17 @@ const [Grid, gridApi] = useVbenVxeGrid({ }, rowConfig: { keyField: 'id', + isHover: true, }, toolbarConfig: { refresh: { code: 'query' }, search: true, }, } as VxeTableGridOptions, + gridEvents: { + checkboxAll: handleRowCheckboxChange, + checkboxChange: handleRowCheckboxChange, + }, }); @@ -129,6 +160,15 @@ const [Grid, gridApi] = useVbenVxeGrid({ auth: ['system:notify-template:export'], onClick: handleExport, }, + { + label: '批量删除', + type: 'primary', + danger: true, + disabled: isEmpty(checkedIds), + icon: ACTION_ICON.DELETE, + auth: ['system:notify-template:delete'], + onClick: handleDeleteBatch, + }, ]" /> diff --git a/apps/web-antd/src/views/system/oauth2/token/data.ts b/apps/web-antd/src/views/system/oauth2/token/data.ts index d990000c6..3222c8731 100644 --- a/apps/web-antd/src/views/system/oauth2/token/data.ts +++ b/apps/web-antd/src/views/system/oauth2/token/data.ts @@ -37,6 +37,7 @@ export function useGridFormSchema(): VbenFormSchema[] { /** 列表的字段 */ export function useGridColumns(): VxeTableGridOptions['columns'] { return [ + { type: 'checkbox', width: 40 }, { field: 'accessToken', title: '访问令牌', diff --git a/apps/web-antd/src/views/system/oauth2/token/index.vue b/apps/web-antd/src/views/system/oauth2/token/index.vue index 3bb0a863e..cd5310bd2 100644 --- a/apps/web-antd/src/views/system/oauth2/token/index.vue +++ b/apps/web-antd/src/views/system/oauth2/token/index.vue @@ -2,6 +2,8 @@ import type { VxeTableGridOptions } from '#/adapter/vxe-table'; import type { SystemOAuth2TokenApi } from '#/api/system/oauth2/token'; +import { ref } from 'vue'; + import { DocAlert, Page } from '@vben/common-ui'; import { message } from 'ant-design-vue'; @@ -9,6 +11,7 @@ import { message } from 'ant-design-vue'; import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; import { deleteOAuth2Token, + deleteOAuth2TokenList, getOAuth2TokenPage, } from '#/api/system/oauth2/token'; import { $t } from '#/locales'; @@ -38,6 +41,41 @@ async function handleDelete(row: SystemOAuth2TokenApi.OAuth2Token) { } } +// 选中的令牌ID +const checkedAccessTokens = ref([]); + +/** 处理表格选择变化 */ +function handleSelectionChange({ + selectRecords, +}: { + selectRecords: SystemOAuth2TokenApi.OAuth2Token[]; +}) { + checkedAccessTokens.value = selectRecords.map((row) => row.accessToken); +} + +/** 批量删除处理 */ +async function handleDeleteBatch() { + if (checkedAccessTokens.value.length === 0) { + message.warning('请至少选择一条数据'); + return; + } + const hideLoading = message.loading({ + content: $t('ui.actionMessage.deleting', ['令牌']), + key: 'action_key_msg', + }); + try { + await deleteOAuth2TokenList(checkedAccessTokens.value); + message.success({ + content: $t('ui.actionMessage.deleteSuccess', ['令牌']), + key: 'action_key_msg', + }); + checkedAccessTokens.value = []; + onRefresh(); + } finally { + hideLoading(); + } +} + const [Grid, gridApi] = useVbenVxeGrid({ formOptions: { schema: useGridFormSchema(), @@ -63,6 +101,18 @@ const [Grid, gridApi] = useVbenVxeGrid({ toolbarConfig: { refresh: { code: 'query' }, search: true, + slots: { + buttons: 'toolbar_buttons', + }, + }, + checkboxConfig: { + checkField: 'checked', + trigger: 'row', + highlight: true, + range: true, + }, + events: { + checkboxChange: handleSelectionChange, }, } as VxeTableGridOptions, }); @@ -78,6 +128,20 @@ const [Grid, gridApi] = useVbenVxeGrid({ + diff --git a/apps/web-antd/src/views/system/role/data.ts b/apps/web-antd/src/views/system/role/data.ts index 30ee7a3d8..1eb3ef155 100644 --- a/apps/web-antd/src/views/system/role/data.ts +++ b/apps/web-antd/src/views/system/role/data.ts @@ -186,6 +186,7 @@ export function useGridFormSchema(): VbenFormSchema[] { /** 列表的字段 */ export function useGridColumns(): VxeTableGridOptions['columns'] { return [ + { type: 'checkbox', width: 40 }, { field: 'id', title: '角色编号', diff --git a/apps/web-antd/src/views/system/role/index.vue b/apps/web-antd/src/views/system/role/index.vue index dcd3b5a82..51bca4692 100644 --- a/apps/web-antd/src/views/system/role/index.vue +++ b/apps/web-antd/src/views/system/role/index.vue @@ -2,13 +2,20 @@ import type { VxeTableGridOptions } from '#/adapter/vxe-table'; import type { SystemRoleApi } from '#/api/system/role'; +import { ref } from 'vue'; + import { DocAlert, Page, useVbenModal } from '@vben/common-ui'; -import { downloadFileFromBlobPart } from '@vben/utils'; +import { downloadFileFromBlobPart, isEmpty } from '@vben/utils'; import { message } from 'ant-design-vue'; import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; -import { deleteRole, exportRole, getRolePage } from '#/api/system/role'; +import { + deleteRole, + deleteRoleList, + exportRole, + getRolePage, +} from '#/api/system/role'; import { $t } from '#/locales'; import { useGridColumns, useGridFormSchema } from './data'; @@ -21,17 +28,16 @@ const [FormModal, formModalApi] = useVbenModal({ destroyOnClose: true, }); -const [AssignDataPermissionFormModel, assignDataPermissionFormApi] = - useVbenModal({ - connectedComponent: AssignDataPermissionForm, - destroyOnClose: true, - }); - -const [AssignMenuFormModel, assignMenuFormApi] = useVbenModal({ +const [AssignMenuModal, assignMenuModalApi] = useVbenModal({ connectedComponent: AssignMenuForm, destroyOnClose: true, }); +const [AssignDataPermissionModal, assignDataPermissionModalApi] = useVbenModal({ + connectedComponent: AssignDataPermissionForm, + destroyOnClose: true, +}); + /** 刷新表格 */ function onRefresh() { gridApi.query(); @@ -40,12 +46,7 @@ function onRefresh() { /** 导出表格 */ async function handleExport() { const data = await exportRole(await gridApi.formApi.getValues()); - downloadFileFromBlobPart({ fileName: '角色.xls', source: data }); -} - -/** 编辑角色 */ -function handleEdit(row: SystemRoleApi.Role) { - formModalApi.setData(row).open(); + downloadFileFromBlobPart({ fileName: '角色数据.xls', source: data }); } /** 创建角色 */ @@ -53,32 +54,60 @@ function handleCreate() { formModalApi.setData(null).open(); } +/** 编辑角色 */ +function handleEdit(row: SystemRoleApi.Role) { + formModalApi.setData(row).open(); +} + /** 删除角色 */ async function handleDelete(row: SystemRoleApi.Role) { const hideLoading = message.loading({ content: $t('ui.actionMessage.deleting', [row.name]), - key: 'action_key_msg', + duration: 0, + key: 'action_process_msg', }); try { await deleteRole(row.id as number); - message.success({ - content: $t('ui.actionMessage.deleteSuccess', [row.name]), - key: 'action_key_msg', - }); + message.success($t('ui.actionMessage.deleteSuccess', [row.name])); onRefresh(); } finally { hideLoading(); } } -/** 分配角色的数据权限 */ -function handleAssignDataPermission(row: SystemRoleApi.Role) { - assignDataPermissionFormApi.setData(row).open(); +const checkedIds = ref([]); +function handleRowCheckboxChange({ + records, +}: { + records: SystemRoleApi.Role[]; +}) { + checkedIds.value = records.map((item) => item.id as number); } -/** 分配角色的菜单权限 */ +/** 批量删除角色 */ +async function handleDeleteBatch() { + const hideLoading = message.loading({ + content: $t('ui.actionMessage.deleting'), + duration: 0, + key: 'action_process_msg', + }); + try { + await deleteRoleList(checkedIds.value); + message.success($t('ui.actionMessage.deleteSuccess')); + onRefresh(); + } finally { + hideLoading(); + } +} + +/** 分配菜单 */ function handleAssignMenu(row: SystemRoleApi.Role) { - assignMenuFormApi.setData(row).open(); + assignMenuModalApi.setData(row).open(); +} + +/** 分配数据权限 */ +function handleAssignDataPermission(row: SystemRoleApi.Role) { + assignDataPermissionModalApi.setData(row).open(); } const [Grid, gridApi] = useVbenVxeGrid({ @@ -88,12 +117,11 @@ const [Grid, gridApi] = useVbenVxeGrid({ gridOptions: { columns: useGridColumns(), height: 'auto', - keepSource: true, proxyConfig: { ajax: { query: async ({ page }, formValues) => { return await getRolePage({ - page: page.currentPage, + pageNo: page.currentPage, pageSize: page.pageSize, ...formValues, }); @@ -102,12 +130,17 @@ const [Grid, gridApi] = useVbenVxeGrid({ }, rowConfig: { keyField: 'id', + isHover: true, }, toolbarConfig: { refresh: { code: 'query' }, search: true, }, } as VxeTableGridOptions, + gridEvents: { + checkboxAll: handleRowCheckboxChange, + checkboxChange: handleRowCheckboxChange, + }, }); @@ -122,8 +155,8 @@ const [Grid, gridApi] = useVbenVxeGrid({ - - + + @@ -169,17 +211,17 @@ const [Grid, gridApi] = useVbenVxeGrid({ ]" :drop-down-actions="[ { - label: '数据权限', - type: 'link', - auth: ['system:permission:assign-role-data-scope'], - onClick: handleAssignDataPermission.bind(null, row), - }, - { - label: '菜单权限', + label: '分配菜单', type: 'link', auth: ['system:permission:assign-role-menu'], onClick: handleAssignMenu.bind(null, row), }, + { + label: '分配数据权限', + type: 'link', + auth: ['system:permission:assign-role-data-scope'], + onClick: handleAssignDataPermission.bind(null, row), + }, ]" /> diff --git a/apps/web-antd/src/views/system/sms/template/data.ts b/apps/web-antd/src/views/system/sms/template/data.ts index f56273cdb..d7f12f64a 100644 --- a/apps/web-antd/src/views/system/sms/template/data.ts +++ b/apps/web-antd/src/views/system/sms/template/data.ts @@ -202,6 +202,7 @@ export function useSendSmsFormSchema(): VbenFormSchema[] { /** 列表的字段 */ export function useGridColumns(): VxeTableGridOptions['columns'] { return [ + { type: 'checkbox', width: 40 }, { field: 'id', title: '编号', diff --git a/apps/web-antd/src/views/system/sms/template/index.vue b/apps/web-antd/src/views/system/sms/template/index.vue index 1f229df98..cc664a335 100644 --- a/apps/web-antd/src/views/system/sms/template/index.vue +++ b/apps/web-antd/src/views/system/sms/template/index.vue @@ -2,14 +2,17 @@ import type { VxeTableGridOptions } from '#/adapter/vxe-table'; import type { SystemSmsTemplateApi } from '#/api/system/sms/template'; +import { ref } from 'vue'; + import { DocAlert, Page, useVbenModal } from '@vben/common-ui'; -import { downloadFileFromBlobPart } from '@vben/utils'; +import { downloadFileFromBlobPart, isEmpty } from '@vben/utils'; import { message } from 'ant-design-vue'; import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; import { deleteSmsTemplate, + deleteSmsTemplateList, exportSmsTemplate, getSmsTemplatePage, } from '#/api/system/sms/template'; @@ -59,14 +62,37 @@ function handleSend(row: SystemSmsTemplateApi.SmsTemplate) { async function handleDelete(row: SystemSmsTemplateApi.SmsTemplate) { const hideLoading = message.loading({ content: $t('ui.actionMessage.deleting', [row.name]), - key: 'action_key_msg', + duration: 0, + key: 'action_process_msg', }); try { await deleteSmsTemplate(row.id as number); - message.success({ - content: $t('ui.actionMessage.deleteSuccess', [row.name]), - key: 'action_key_msg', - }); + message.success($t('ui.actionMessage.deleteSuccess', [row.name])); + onRefresh(); + } finally { + hideLoading(); + } +} + +const checkedIds = ref([]); +function handleRowCheckboxChange({ + records, +}: { + records: SystemSmsTemplateApi.SmsTemplate[]; +}) { + checkedIds.value = records.map((item) => item.id as number); +} + +/** 批量删除短信模板 */ +async function handleDeleteBatch() { + const hideLoading = message.loading({ + content: $t('ui.actionMessage.deleting'), + duration: 0, + key: 'action_process_msg', + }); + try { + await deleteSmsTemplateList(checkedIds.value); + message.success($t('ui.actionMessage.deleteSuccess')); onRefresh(); } finally { hideLoading(); @@ -94,12 +120,17 @@ const [Grid, gridApi] = useVbenVxeGrid({ }, rowConfig: { keyField: 'id', + isHover: true, }, toolbarConfig: { refresh: { code: 'query' }, search: true, }, } as VxeTableGridOptions, + gridEvents: { + checkboxAll: handleRowCheckboxChange, + checkboxChange: handleRowCheckboxChange, + }, }); @@ -129,6 +160,15 @@ const [Grid, gridApi] = useVbenVxeGrid({ auth: ['system:sms-template:export'], onClick: handleExport, }, + { + label: '批量删除', + type: 'primary', + danger: true, + disabled: isEmpty(checkedIds), + icon: ACTION_ICON.DELETE, + auth: ['system:sms-template:delete'], + onClick: handleDeleteBatch, + }, ]" /> diff --git a/apps/web-antd/src/views/system/tenant/data.ts b/apps/web-antd/src/views/system/tenant/data.ts index 30b2a79d5..cdc5e2c6a 100644 --- a/apps/web-antd/src/views/system/tenant/data.ts +++ b/apps/web-antd/src/views/system/tenant/data.ts @@ -161,6 +161,7 @@ export function useGridColumns( getPackageName?: (packageId: number) => string | undefined, ): VxeTableGridOptions['columns'] { return [ + { type: 'checkbox', width: 40 }, { field: 'id', title: '租户编号', diff --git a/apps/web-antd/src/views/system/tenant/index.vue b/apps/web-antd/src/views/system/tenant/index.vue index d57148ade..b0ddd0f08 100644 --- a/apps/web-antd/src/views/system/tenant/index.vue +++ b/apps/web-antd/src/views/system/tenant/index.vue @@ -6,12 +6,17 @@ import type { SystemTenantPackageApi } from '#/api/system/tenant-package'; import { onMounted, ref } from 'vue'; import { DocAlert, Page, useVbenModal } from '@vben/common-ui'; -import { downloadFileFromBlobPart } from '@vben/utils'; +import { downloadFileFromBlobPart, isEmpty } from '@vben/utils'; import { message } from 'ant-design-vue'; import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; -import { deleteTenant, exportTenant, getTenantPage } from '#/api/system/tenant'; +import { + deleteTenant, + deleteTenantList, + exportTenant, + getTenantPage, +} from '#/api/system/tenant'; import { getTenantPackageList } from '#/api/system/tenant-package'; import { $t } from '#/locales'; @@ -58,14 +63,37 @@ function handleEdit(row: SystemTenantApi.Tenant) { async function handleDelete(row: SystemTenantApi.Tenant) { const hideLoading = message.loading({ content: $t('ui.actionMessage.deleting', [row.name]), - key: 'action_key_msg', + duration: 0, + key: 'action_process_msg', }); try { await deleteTenant(row.id as number); - message.success({ - content: $t('ui.actionMessage.deleteSuccess', [row.name]), - key: 'action_key_msg', - }); + message.success($t('ui.actionMessage.deleteSuccess', [row.name])); + onRefresh(); + } finally { + hideLoading(); + } +} + +const checkedIds = ref([]); +function handleRowCheckboxChange({ + records, +}: { + records: SystemTenantApi.Tenant[]; +}) { + checkedIds.value = records.map((item) => item.id as number); +} + +/** 批量删除租户 */ +async function handleDeleteBatch() { + const hideLoading = message.loading({ + content: $t('ui.actionMessage.deleting'), + duration: 0, + key: 'action_process_msg', + }); + try { + await deleteTenantList(checkedIds.value); + message.success($t('ui.actionMessage.deleteSuccess')); onRefresh(); } finally { hideLoading(); @@ -91,12 +119,17 @@ const [Grid, gridApi] = useVbenVxeGrid({ }, rowConfig: { keyField: 'id', + isHover: true, }, toolbarConfig: { refresh: { code: 'query' }, search: true, }, } as VxeTableGridOptions, + gridEvents: { + checkboxAll: handleRowCheckboxChange, + checkboxChange: handleRowCheckboxChange, + }, }); /** 初始化 */ @@ -129,6 +162,15 @@ onMounted(async () => { auth: ['system:tenant:export'], onClick: handleExport, }, + { + label: '批量删除', + type: 'primary', + danger: true, + disabled: isEmpty(checkedIds), + icon: ACTION_ICON.DELETE, + auth: ['system:tenant:delete'], + onClick: handleDeleteBatch, + }, ]" /> diff --git a/apps/web-antd/src/views/system/tenantPackage/data.ts b/apps/web-antd/src/views/system/tenantPackage/data.ts index 66775f892..7826f9c7b 100644 --- a/apps/web-antd/src/views/system/tenantPackage/data.ts +++ b/apps/web-antd/src/views/system/tenantPackage/data.ts @@ -88,6 +88,7 @@ export function useGridFormSchema(): VbenFormSchema[] { /** 列表的字段 */ export function useGridColumns(): VxeTableGridOptions['columns'] { return [ + { type: 'checkbox', width: 40 }, { field: 'id', title: '套餐编号', diff --git a/apps/web-antd/src/views/system/tenantPackage/index.vue b/apps/web-antd/src/views/system/tenantPackage/index.vue index 3cee7fbb1..3f0a210b2 100644 --- a/apps/web-antd/src/views/system/tenantPackage/index.vue +++ b/apps/web-antd/src/views/system/tenantPackage/index.vue @@ -2,13 +2,17 @@ import type { VxeTableGridOptions } from '#/adapter/vxe-table'; import type { SystemTenantPackageApi } from '#/api/system/tenant-package'; +import { ref } from 'vue'; + import { DocAlert, Page, useVbenModal } from '@vben/common-ui'; +import { isEmpty } from '@vben/utils'; import { message } from 'ant-design-vue'; import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; import { deleteTenantPackage, + deleteTenantPackageList, getTenantPackagePage, } from '#/api/system/tenant-package'; import { $t } from '#/locales'; @@ -40,14 +44,37 @@ function handleEdit(row: SystemTenantPackageApi.TenantPackage) { async function handleDelete(row: SystemTenantPackageApi.TenantPackage) { const hideLoading = message.loading({ content: $t('ui.actionMessage.deleting', [row.name]), - key: 'action_key_msg', + duration: 0, + key: 'action_process_msg', }); try { await deleteTenantPackage(row.id as number); - message.success({ - content: $t('ui.actionMessage.deleteSuccess', [row.name]), - key: 'action_key_msg', - }); + message.success($t('ui.actionMessage.deleteSuccess', [row.name])); + onRefresh(); + } finally { + hideLoading(); + } +} + +const checkedIds = ref([]); +function handleRowCheckboxChange({ + records, +}: { + records: SystemTenantPackageApi.TenantPackage[]; +}) { + checkedIds.value = records.map((item) => item.id as number); +} + +/** 批量删除租户套餐 */ +async function handleDeleteBatch() { + const hideLoading = message.loading({ + content: $t('ui.actionMessage.deleting'), + duration: 0, + key: 'action_process_msg', + }); + try { + await deleteTenantPackageList(checkedIds.value); + message.success($t('ui.actionMessage.deleteSuccess')); onRefresh(); } finally { hideLoading(); @@ -75,12 +102,17 @@ const [Grid, gridApi] = useVbenVxeGrid({ }, rowConfig: { keyField: 'id', + isHover: true, }, toolbarConfig: { refresh: { code: 'query' }, search: true, }, } as VxeTableGridOptions, + gridEvents: { + checkboxAll: handleRowCheckboxChange, + checkboxChange: handleRowCheckboxChange, + }, }); @@ -102,6 +134,15 @@ const [Grid, gridApi] = useVbenVxeGrid({ auth: ['system:tenant-package:create'], onClick: handleCreate, }, + { + label: '批量删除', + type: 'primary', + danger: true, + disabled: isEmpty(checkedIds), + icon: ACTION_ICON.DELETE, + auth: ['system:tenant-package:delete'], + onClick: handleDeleteBatch, + }, ]" /> diff --git a/apps/web-antd/src/views/system/user/data.ts b/apps/web-antd/src/views/system/user/data.ts index ae2c06ff0..8ec46607d 100644 --- a/apps/web-antd/src/views/system/user/data.ts +++ b/apps/web-antd/src/views/system/user/data.ts @@ -265,6 +265,7 @@ export function useGridColumns( ) => PromiseLike, ): VxeTableGridOptions['columns'] { return [ + { type: 'checkbox', width: 40 }, { field: 'id', title: '用户编号', diff --git a/apps/web-antd/src/views/system/user/index.vue b/apps/web-antd/src/views/system/user/index.vue index 2cd7d060b..401848abf 100644 --- a/apps/web-antd/src/views/system/user/index.vue +++ b/apps/web-antd/src/views/system/user/index.vue @@ -1,28 +1,28 @@ From 2939c2e4f592969dcf3c269ba38f0714165e699d Mon Sep 17 00:00:00 2001 From: puhui999 Date: Sun, 15 Jun 2025 17:52:03 +0800 Subject: [PATCH 3/4] =?UTF-8?q?feat:=20=E3=80=90antd=E3=80=91=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E6=89=B9=E9=87=8F=E5=88=A0=E9=99=A4=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/views/system/sms/channel/data.ts | 1 + .../src/views/system/sms/channel/index.vue | 57 ++++++++++++++++++- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/apps/web-antd/src/views/system/sms/channel/data.ts b/apps/web-antd/src/views/system/sms/channel/data.ts index 18efe62f0..f00ea26d5 100644 --- a/apps/web-antd/src/views/system/sms/channel/data.ts +++ b/apps/web-antd/src/views/system/sms/channel/data.ts @@ -132,6 +132,7 @@ export function useGridFormSchema(): VbenFormSchema[] { /** 列表的字段 */ export function useGridColumns(): VxeTableGridOptions['columns'] { return [ + { type: 'checkbox', width: 40 }, { field: 'id', title: '编号', diff --git a/apps/web-antd/src/views/system/sms/channel/index.vue b/apps/web-antd/src/views/system/sms/channel/index.vue index bb9cbcfcf..f172f155f 100644 --- a/apps/web-antd/src/views/system/sms/channel/index.vue +++ b/apps/web-antd/src/views/system/sms/channel/index.vue @@ -2,14 +2,17 @@ import type { VxeTableGridOptions } from '#/adapter/vxe-table'; import type { SystemSmsChannelApi } from '#/api/system/sms/channel'; +import { ref } from 'vue'; + import { DocAlert, Page, useVbenModal } from '@vben/common-ui'; -import { downloadFileFromBlobPart } from '@vben/utils'; +import { downloadFileFromBlobPart, isEmpty } from '@vben/utils'; import { message } from 'ant-design-vue'; import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; import { deleteSmsChannel, + deleteSmsChannelList, exportSmsChannel, getSmsChannelPage, } from '#/api/system/sms/channel'; @@ -62,6 +65,39 @@ async function handleDelete(row: SystemSmsChannelApi.SmsChannel) { } } +// 选中的短信渠道ID +const checkedIds = ref([]); +function handleRowCheckboxChange({ + records, +}: { + records: SystemSmsChannelApi.SmsChannel[]; +}) { + checkedIds.value = records.map((item) => item.id as number); +} + +/** 批量删除处理 */ +async function handleDeleteBatch() { + if (checkedIds.value.length === 0) { + message.warning('请至少选择一条数据'); + return; + } + const hideLoading = message.loading({ + content: $t('ui.actionMessage.deleting', ['短信渠道']), + key: 'action_key_msg', + }); + try { + await deleteSmsChannelList(checkedIds.value); + message.success({ + content: $t('ui.actionMessage.deleteSuccess', ['短信渠道']), + key: 'action_key_msg', + }); + checkedIds.value = []; + onRefresh(); + } finally { + hideLoading(); + } +} + const [Grid, gridApi] = useVbenVxeGrid({ formOptions: { schema: useGridFormSchema(), @@ -83,12 +119,20 @@ const [Grid, gridApi] = useVbenVxeGrid({ }, rowConfig: { keyField: 'id', + isHover: true, }, toolbarConfig: { refresh: { code: 'query' }, search: true, }, + checkboxConfig: { + checkField: 'checked', + }, } as VxeTableGridOptions, + gridEvents: { + checkboxAll: handleRowCheckboxChange, + checkboxChange: handleRowCheckboxChange, + }, }); @@ -117,6 +161,15 @@ const [Grid, gridApi] = useVbenVxeGrid({ auth: ['system:sms-channel:export'], onClick: handleExport, }, + { + label: '批量删除', + type: 'primary', + danger: true, + disabled: isEmpty(checkedIds), + icon: ACTION_ICON.DELETE, + auth: ['system:sms-channel:delete'], + onClick: handleDeleteBatch, + }, ]" /> @@ -137,7 +190,7 @@ const [Grid, gridApi] = useVbenVxeGrid({ icon: ACTION_ICON.DELETE, auth: ['system:sms-channel:delete'], popConfirm: { - title: $t('ui.actionMessage.deleteConfirm', [row.name]), + title: $t('ui.actionMessage.deleteConfirm', [row.signature]), confirm: handleDelete.bind(null, row), }, }, From 0d411310fe24d2d9b65bc215a06acacd9885de94 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Sun, 15 Jun 2025 21:09:40 +0800 Subject: [PATCH 4/4] =?UTF-8?q?fix:=20=E3=80=90antd=E3=80=91=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E6=B7=BB=E5=8A=A0=E6=89=B9=E9=87=8F=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E6=97=B6=E4=BA=A7=E7=94=9F=E7=9A=84=E5=89=AF=E4=BD=9C=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web-antd/src/views/system/dept/index.vue | 8 +- .../views/system/dict/modules/data-grid.vue | 8 +- .../views/system/dict/modules/type-grid.vue | 8 +- .../src/views/system/mail/account/index.vue | 8 +- .../src/views/system/mail/template/index.vue | 15 +- apps/web-antd/src/views/system/menu/data.ts | 1 - apps/web-antd/src/views/system/menu/index.vue | 102 +++---- .../src/views/system/notice/index.vue | 13 +- .../views/system/notify/template/index.vue | 8 +- .../src/views/system/oauth2/token/index.vue | 64 ----- apps/web-antd/src/views/system/post/index.vue | 8 +- apps/web-antd/src/views/system/role/index.vue | 64 +++-- .../src/views/system/sms/template/index.vue | 8 +- .../src/views/system/tenant/index.vue | 8 +- .../src/views/system/tenantPackage/index.vue | 8 +- apps/web-antd/src/views/system/user/index.vue | 265 ++++++++++-------- 16 files changed, 281 insertions(+), 315 deletions(-) diff --git a/apps/web-antd/src/views/system/dept/index.vue b/apps/web-antd/src/views/system/dept/index.vue index f8d875af9..638865004 100644 --- a/apps/web-antd/src/views/system/dept/index.vue +++ b/apps/web-antd/src/views/system/dept/index.vue @@ -61,12 +61,14 @@ function handleEdit(row: SystemDeptApi.Dept) { async function handleDelete(row: SystemDeptApi.Dept) { const hideLoading = message.loading({ content: $t('ui.actionMessage.deleting', [row.name]), - duration: 0, - key: 'action_process_msg', + key: 'action_key_msg', }); try { await deleteDept(row.id as number); - message.success($t('ui.actionMessage.deleteSuccess', [row.name])); + message.success({ + content: $t('ui.actionMessage.deleteSuccess', [row.name]), + key: 'action_key_msg', + }); onRefresh(); } finally { hideLoading(); diff --git a/apps/web-antd/src/views/system/dict/modules/data-grid.vue b/apps/web-antd/src/views/system/dict/modules/data-grid.vue index d94351ff4..7079c8adb 100644 --- a/apps/web-antd/src/views/system/dict/modules/data-grid.vue +++ b/apps/web-antd/src/views/system/dict/modules/data-grid.vue @@ -58,12 +58,14 @@ function handleEdit(row: SystemDictDataApi.DictData) { async function handleDelete(row: SystemDictDataApi.DictData) { const hideLoading = message.loading({ content: $t('ui.actionMessage.deleting', [row.label]), - duration: 0, - key: 'action_process_msg', + key: 'action_key_msg', }); try { await deleteDictData(row.id as number); - message.success($t('ui.actionMessage.deleteSuccess', [row.label])); + message.success({ + content: $t('ui.actionMessage.deleteSuccess', [row.label]), + key: 'action_key_msg', + }); onRefresh(); } finally { hideLoading(); diff --git a/apps/web-antd/src/views/system/dict/modules/type-grid.vue b/apps/web-antd/src/views/system/dict/modules/type-grid.vue index 2c6fce228..98600900c 100644 --- a/apps/web-antd/src/views/system/dict/modules/type-grid.vue +++ b/apps/web-antd/src/views/system/dict/modules/type-grid.vue @@ -56,12 +56,14 @@ function handleEdit(row: any) { async function handleDelete(row: SystemDictTypeApi.DictType) { const hideLoading = message.loading({ content: $t('ui.actionMessage.deleting', [row.name]), - duration: 0, - key: 'action_process_msg', + key: 'action_key_msg', }); try { await deleteDictType(row.id as number); - message.success($t('ui.actionMessage.deleteSuccess', [row.name])); + message.success({ + content: $t('ui.actionMessage.deleteSuccess', [row.name]), + key: 'action_key_msg', + }); onRefresh(); } finally { hideLoading(); diff --git a/apps/web-antd/src/views/system/mail/account/index.vue b/apps/web-antd/src/views/system/mail/account/index.vue index 3da0308b9..e7344f424 100644 --- a/apps/web-antd/src/views/system/mail/account/index.vue +++ b/apps/web-antd/src/views/system/mail/account/index.vue @@ -44,12 +44,14 @@ function handleEdit(row: SystemMailAccountApi.MailAccount) { async function handleDelete(row: SystemMailAccountApi.MailAccount) { const hideLoading = message.loading({ content: $t('ui.actionMessage.deleting', [row.mail]), - duration: 0, - key: 'action_process_msg', + key: 'action_key_msg', }); try { await deleteMailAccount(row.id as number); - message.success($t('ui.actionMessage.deleteSuccess', [row.mail])); + message.success({ + content: $t('ui.actionMessage.deleteSuccess', [row.mail]), + key: 'action_key_msg', + }); onRefresh(); } finally { hideLoading(); diff --git a/apps/web-antd/src/views/system/mail/template/index.vue b/apps/web-antd/src/views/system/mail/template/index.vue index b0bf5fcce..c45b3e714 100644 --- a/apps/web-antd/src/views/system/mail/template/index.vue +++ b/apps/web-antd/src/views/system/mail/template/index.vue @@ -57,18 +57,17 @@ function handleSend(row: SystemMailTemplateApi.MailTemplate) { /** 删除邮件模板 */ async function handleDelete(row: SystemMailTemplateApi.MailTemplate) { - const hideLoading = message.loading({ + message.loading({ content: $t('ui.actionMessage.deleting', [row.name]), duration: 0, key: 'action_process_msg', }); - try { - await deleteMailTemplate(row.id as number); - message.success($t('ui.actionMessage.deleteSuccess', [row.name])); - onRefresh(); - } finally { - hideLoading(); - } + await deleteMailTemplate(row.id as number); + message.success({ + content: $t('ui.actionMessage.deleteSuccess', [row.name]), + key: 'action_key_msg', + }); + onRefresh(); } const checkedIds = ref([]); diff --git a/apps/web-antd/src/views/system/menu/data.ts b/apps/web-antd/src/views/system/menu/data.ts index 0c9c49f2e..0cc5a6a86 100644 --- a/apps/web-antd/src/views/system/menu/data.ts +++ b/apps/web-antd/src/views/system/menu/data.ts @@ -268,7 +268,6 @@ export function useFormSchema(): VbenFormSchema[] { /** 列表的字段 */ export function useGridColumns(): VxeTableGridOptions['columns'] { return [ - { type: 'checkbox', width: 40 }, { field: 'name', title: '菜单名称', diff --git a/apps/web-antd/src/views/system/menu/index.vue b/apps/web-antd/src/views/system/menu/index.vue index cbf432907..9519bb277 100644 --- a/apps/web-antd/src/views/system/menu/index.vue +++ b/apps/web-antd/src/views/system/menu/index.vue @@ -6,12 +6,11 @@ import { ref } from 'vue'; import { DocAlert, Page, useVbenModal } from '@vben/common-ui'; import { IconifyIcon } from '@vben/icons'; -import { isEmpty } from '@vben/utils'; import { message } from 'ant-design-vue'; import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; -import { deleteMenu, deleteMenuList, getMenuList } from '#/api/system/menu'; +import { deleteMenu, getMenuList } from '#/api/system/menu'; import { $t } from '#/locales'; import { SystemMenuTypeEnum } from '#/utils'; @@ -29,8 +28,13 @@ function onRefresh() { } /** 创建菜单 */ -function handleCreate(parentId?: number) { - formModalApi.setData({ parentId: parentId || 0 }).open(); +function handleCreate() { + formModalApi.setData({}).open(); +} + +/** 添加下级菜单 */ +function handleAppend(row: SystemMenuApi.Menu) { + formModalApi.setData({ pid: row.id }).open(); } /** 编辑菜单 */ @@ -42,74 +46,55 @@ function handleEdit(row: SystemMenuApi.Menu) { async function handleDelete(row: SystemMenuApi.Menu) { const hideLoading = message.loading({ content: $t('ui.actionMessage.deleting', [row.name]), - duration: 0, - key: 'action_process_msg', + key: 'action_key_msg', }); try { - await deleteMenu(row.id); - message.success($t('ui.actionMessage.deleteSuccess', [row.name])); + await deleteMenu(row.id as number); + message.success({ + content: $t('ui.actionMessage.deleteSuccess', [row.name]), + key: 'action_key_msg', + }); onRefresh(); } finally { hideLoading(); } } -const checkedIds = ref([]); -function handleRowCheckboxChange({ - records, -}: { - records: SystemMenuApi.Menu[]; -}) { - checkedIds.value = records.map((item) => item.id); -} - -/** 批量删除菜单 */ -async function handleDeleteBatch() { - const hideLoading = message.loading({ - content: $t('ui.actionMessage.deleting'), - duration: 0, - key: 'action_process_msg', - }); - try { - await deleteMenuList(checkedIds.value); - message.success($t('ui.actionMessage.deleteSuccess')); - onRefresh(); - } finally { - hideLoading(); - } +/** 切换树形展开/收缩状态 */ +const isExpanded = ref(false); +function toggleExpand() { + isExpanded.value = !isExpanded.value; + gridApi.grid.setAllTreeExpand(isExpanded.value); } const [Grid, gridApi] = useVbenVxeGrid({ gridOptions: { columns: useGridColumns(), height: 'auto', + keepSource: true, + pagerConfig: { + enabled: false, + }, proxyConfig: { ajax: { - query: async () => { + query: async (_params) => { return await getMenuList(); }, }, }, - treeConfig: { - transform: true, - rowField: 'id', - parentField: 'parentId', - expandAll: true, - accordion: false, - }, rowConfig: { keyField: 'id', - isHover: true, }, toolbarConfig: { refresh: { code: 'query' }, - search: true, }, - } as VxeTableGridOptions, - gridEvents: { - checkboxAll: handleRowCheckboxChange, - checkboxChange: handleRowCheckboxChange, - }, + treeConfig: { + parentField: 'parentId', + rowField: 'id', + transform: true, + reserve: true, + }, + } as VxeTableGridOptions, }); @@ -124,7 +109,7 @@ const [Grid, gridApi] = useVbenVxeGrid({ - + -