diff --git a/src/api/org.ts b/src/api/org.ts index 8d53cc2..aac393c 100644 --- a/src/api/org.ts +++ b/src/api/org.ts @@ -37,3 +37,8 @@ export function updateOrg( export function deleteOrg(id: string): Promise { return http.delete(`/orgs/${id}`) } + +/** 批量删除组织。 */ +export function batchDeleteOrgs(ids: string[]): Promise<{ total: number; success: number; failed: string[] }> { + return http.post('/orgs/batch-delete', { ids }) +} diff --git a/src/api/resource.ts b/src/api/resource.ts index e9b59ff..5929505 100644 --- a/src/api/resource.ts +++ b/src/api/resource.ts @@ -49,3 +49,8 @@ export function updateResource(id: string, data: ResourceUpsertData): Promise { return http.delete(`/resources/${id}`) } + +/** 批量删除资源。 */ +export function batchDeleteResources(ids: string[]): Promise<{ total: number; success: number; failed: string[] }> { + return http.post('/resources/batch-delete', { ids }) +} diff --git a/src/api/role.ts b/src/api/role.ts index c2197d5..495b5d8 100644 --- a/src/api/role.ts +++ b/src/api/role.ts @@ -60,3 +60,13 @@ export function listAssignedResources(roleCode: string, signal?: AbortSignal): P export function assignResources(roleCode: string, resourceCodes: string[]): Promise { return http.put(`/roles/${roleCode}/resources`, { resourceCodes }) } + +/** 角色已分配的数据权限部门 code 列表(data_scope=custom)。 */ +export function listAssignedOrgs(roleCode: string, signal?: AbortSignal): Promise { + return http.get(`/roles/${roleCode}/orgs`, { signal }) +} + +/** 分配数据权限部门。 */ +export function assignOrgs(roleCode: string, orgCodes: string[]): Promise { + return http.put(`/roles/${roleCode}/orgs`, { orgCodes }) +} diff --git a/src/api/user.ts b/src/api/user.ts index 7129a25..84a3091 100644 --- a/src/api/user.ts +++ b/src/api/user.ts @@ -67,6 +67,11 @@ export function deleteUser(id: string): Promise { return http.delete(`/users/${id}`) } +/** 批量删除用户。 */ +export function batchDeleteUsers(ids: string[]): Promise<{ total: number; success: number; failed: string[] }> { + return http.post('/users/batch-delete', { ids }) +} + /** 重置密码。 */ export function resetPassword(id: string, password: string): Promise { return http.patch(`/users/${id}/password`, { password }) diff --git a/src/pages/system/org/index.vue b/src/pages/system/org/index.vue index ba82699..6b4b6bd 100644 --- a/src/pages/system/org/index.vue +++ b/src/pages/system/org/index.vue @@ -46,7 +46,7 @@ import TyForm from '@/components/ty-form.vue' import { showDialog } from '@/utils/dialog' import { useRequest } from '@/composables/useRequest' import { buildTree, collectDescendants, filterTree, type TreeNode } from '@/utils/tree' -import { createOrg, deleteOrg, listOrgs, updateOrg, type Org } from '@/api/org' +import { batchDeleteOrgs, createOrg, deleteOrg, listOrgs, updateOrg, type Org } from '@/api/org' type OrgNode = TreeNode @@ -238,10 +238,14 @@ async function batchDelete(rows: Record[]): Promise { codes.add(String(r.code)) for (const c of collectDescendants(orgs.value, String(r.code))) codes.add(c) } - const targets = orgs.value.filter((o) => codes.has(o.code)) - for (const t of targets) await deleteOrg(t.id) + const ids = orgs.value.filter((o) => codes.has(o.code)).map((o) => o.id) + const result = await batchDeleteOrgs(ids) + if (result.failed.length > 0) { + ElMessage.warning(`删除完成:成功 ${result.success} 个,失败 ${result.failed.length} 个`) + } else { + ElMessage.success('删除成功') + } selectedRows.value = [] - ElMessage.success('删除成功') await refreshOrgs() } diff --git a/src/pages/system/resource/index.vue b/src/pages/system/resource/index.vue index 56639e5..a0c2a3e 100644 --- a/src/pages/system/resource/index.vue +++ b/src/pages/system/resource/index.vue @@ -46,7 +46,7 @@ import TyForm from '@/components/ty-form.vue' import { showDialog } from '@/utils/dialog' import { useRequest } from '@/composables/useRequest' import { buildTree, collectDescendants, filterTree, type TreeNode } from '@/utils/tree' -import { createResource, deleteResource, listResources, updateResource, type Resource, type ResourceUpsertData } from '@/api/resource' +import { batchDeleteResources, createResource, deleteResource, listResources, updateResource, type Resource, type ResourceUpsertData } from '@/api/resource' type ResourceNode = TreeNode @@ -288,10 +288,14 @@ async function batchDelete(rows: Record[]): Promise { codes.add(String(r.code)) for (const c of collectDescendants(resources.value, String(r.code))) codes.add(c) } - const targets = resources.value.filter((o) => codes.has(o.code)) - for (const t of targets) await deleteResource(t.id) + const ids = resources.value.filter((o) => codes.has(o.code)).map((o) => o.id) + const result = await batchDeleteResources(ids) + if (result.failed.length > 0) { + ElMessage.warning(`删除完成:成功 ${result.success} 个,失败 ${result.failed.length} 个`) + } else { + ElMessage.success('删除成功') + } selectedRows.value = [] - ElMessage.success('删除成功') await refreshResources() } diff --git a/src/pages/system/role/assign-orgs-form.vue b/src/pages/system/role/assign-orgs-form.vue new file mode 100644 index 0000000..910840a --- /dev/null +++ b/src/pages/system/role/assign-orgs-form.vue @@ -0,0 +1,57 @@ + + + + + diff --git a/src/pages/system/role/index.vue b/src/pages/system/role/index.vue index 109c957..c11316f 100644 --- a/src/pages/system/role/index.vue +++ b/src/pages/system/role/index.vue @@ -19,8 +19,9 @@ import { ElMessage } from 'element-plus' import type { CrudAction, JsonSchema, PageQuery, TableColumn } from '@/types/crud' import { showDialog } from '@/utils/dialog' -import { assignResources, createRole, deleteRole, listRoles, updateRole, type RoleListQuery } from '@/api/role' +import { assignOrgs, assignResources, createRole, deleteRole, listRoles, updateRole, type RoleListQuery } from '@/api/role' import AssignResourcesForm from './assign-resources-form.vue' +import AssignOrgsForm from './assign-orgs-form.vue' const columns: TableColumn[] = [ { prop: 'name', label: '角色名称', minWidth: 140 }, @@ -72,6 +73,7 @@ const actions: CrudAction[] = [ 'edit', 'delete', { label: '分配权限', type: 'warning', onClick: (row) => assignAction(row) }, + { label: '分配部门', type: 'primary', show: (row) => row.dataScope === 'custom', onClick: (row) => assignOrgsAction(row) }, ] function toListQuery(query: PageQuery): RoleListQuery { @@ -103,4 +105,16 @@ async function assignAction(row: Record): Promise { await assignResources(String(row.code), result.resourceCodes) ElMessage.success('权限已保存') } + +async function assignOrgsAction(row: Record): Promise { + const result = await showDialog({ + component: AssignOrgsForm, + props: { roleCode: String(row.code) }, + title: `分配数据权限部门(${row.name})`, + width: '520px', + }) + if (result == null) return + await assignOrgs(String(row.code), result.orgCodes) + ElMessage.success('部门已保存') +} diff --git a/src/pages/system/user/index.vue b/src/pages/system/user/index.vue index c6c318f..c67b3ad 100644 --- a/src/pages/system/user/index.vue +++ b/src/pages/system/user/index.vue @@ -39,6 +39,7 @@ import { showDialog } from '@/utils/dialog' import { useRequest } from '@/composables/useRequest' import { assignUserRoles, + batchDeleteUsers, createUser, deleteUser, listUsers, @@ -167,10 +168,12 @@ const crudRef = ref() async function batchDelete(rows: Record[]): Promise { await ElMessageBox.confirm(`确认删除选中的 ${rows.length} 个用户?`, '提示', { type: 'warning' }) - for (const r of rows) { - await deleteUser(String(r.id)) + const result = await batchDeleteUsers(rows.map((r) => String(r.id))) + if (result.failed.length > 0) { + ElMessage.warning(`删除完成:成功 ${result.success} 个,失败 ${result.failed.length} 个`) + } else { + ElMessage.success('删除成功') } - ElMessage.success('删除成功') crudRef.value?.reload() } diff --git a/typed-router.d.ts b/typed-router.d.ts index 470712c..ec91c61 100644 --- a/typed-router.d.ts +++ b/typed-router.d.ts @@ -121,6 +121,13 @@ declare module 'vue-router/auto-routes' { Record, | never >, + '/system/role/assign-orgs-form': RouteRecordInfo< + '/system/role/assign-orgs-form', + '/system/role/assign-orgs-form', + Record, + Record, + | never + >, '/system/role/assign-resources-form': RouteRecordInfo< '/system/role/assign-resources-form', '/system/role/assign-resources-form', @@ -253,6 +260,12 @@ declare module 'vue-router/auto-routes' { views: | never } + 'src/pages/system/role/assign-orgs-form.vue': { + routes: + | '/system/role/assign-orgs-form' + views: + | never + } 'src/pages/system/role/assign-resources-form.vue': { routes: | '/system/role/assign-resources-form'