From 0cc83967ed289f1e1e3b02c6d4d4703c38ee0b9f Mon Sep 17 00:00:00 2001 From: puhui999 Date: Sun, 15 Jun 2025 17:02:10 +0800 Subject: [PATCH] =?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 @@