refactor: RoleManagement component with API services and permission assignment

This commit is contained in:
张翔
2026-03-20 08:02:03 +08:00
parent 50c5afbbb7
commit a97d317e4a
@@ -40,27 +40,30 @@
<el-table-column
prop="id"
label="ID"
width="80"
sortable="custom"
/>
<el-table-column
prop="roleName"
prop="name"
label="角色名称"
sortable="custom"
/>
<el-table-column
prop="roleKey"
prop="code"
label="角色标识"
sortable="custom"
/>
<el-table-column
prop="roleSort"
label="排序"
sortable="custom"
prop="description"
label="描述"
/>
<el-table-column label="状态">
<el-table-column
label="状态"
width="100"
>
<template #default="{ row }">
<el-tag :type="row.status === '0' ? 'success' : 'danger'">
{{ row.status === '0' ? '正常' : '禁用' }}
<el-tag :type="row.status === 'ACTIVE' ? 'success' : 'danger'">
{{ row.status === 'ACTIVE' ? '正常' : '禁用' }}
</el-tag>
</template>
</el-table-column>
@@ -71,7 +74,7 @@
/>
<el-table-column
label="操作"
width="200"
width="250"
>
<template #default="{ row }">
<el-button
@@ -81,6 +84,13 @@
>
编辑
</el-button>
<el-button
type="warning"
link
@click="handleAssignPermissions(row)"
>
分配权限
</el-button>
<el-button
type="danger"
link
@@ -112,23 +122,35 @@
:model="formState"
label-width="80px"
>
<el-form-item label="角色名称">
<el-input v-model="formState.roleName" />
<el-form-item
label="角色名称"
required
>
<el-input v-model="formState.name" />
</el-form-item>
<el-form-item label="角色标识">
<el-input v-model="formState.roleKey" />
<el-form-item
label="角色标识"
required
>
<el-input
v-model="formState.code"
:disabled="!!formState.id"
/>
</el-form-item>
<el-form-item label="排序">
<el-input-number v-model="formState.roleSort" />
<el-form-item label="描述">
<el-input
v-model="formState.description"
type="textarea"
/>
</el-form-item>
<el-form-item label="状态">
<el-select v-model="formState.status">
<el-option
value="0"
value="ACTIVE"
label="正常"
/>
<el-option
value="1"
value="INACTIVE"
label="禁用"
/>
</el-select>
@@ -146,6 +168,33 @@
</el-button>
</template>
</el-dialog>
<el-dialog
v-model="permissionDialogVisible"
title="分配权限"
width="600px"
>
<el-tree
ref="permissionTreeRef"
:data="permissionTree"
:props="{ label: 'name', children: 'children' }"
show-checkbox
node-key="id"
:default-checked-keys="selectedPermissions"
check-strictly
/>
<template #footer>
<el-button @click="permissionDialogVisible = false">
取消
</el-button>
<el-button
type="primary"
@click="handleAssignPermissionsOk"
>
确定
</el-button>
</template>
</el-dialog>
</div>
</template>
@@ -153,10 +202,11 @@
import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Search } from '@element-plus/icons-vue'
import request from '@/utils/request'
import { roleApi, type Role, type CreateRoleRequest, type UpdateRoleRequest, type Permission } from '@/api/role.api'
import { handleApiError } from '@/utils/errorHandler'
const loading = ref(false)
const dataSource = ref([])
const dataSource = ref<Role[]>([])
const searchKeyword = ref('')
const pagination = reactive({
current: 1,
@@ -165,28 +215,40 @@ const pagination = reactive({
})
const sortInfo = reactive({
sort: 'id',
order: 'asc'
sortBy: 'id',
sortOrder: 'asc' as 'asc' | 'desc'
})
const modalVisible = ref(false)
const modalTitle = ref('')
const formState = reactive({ id: null, roleName: '', roleKey: '', roleSort: 0, status: '0' })
const formState = reactive<CreateRoleRequest & { id?: number }>({
name: '',
code: '',
description: '',
permissions: [],
status: 'ACTIVE'
})
const permissionDialogVisible = ref(false)
const permissionTreeRef = ref()
const permissionTree = ref<any[]>([])
const selectedPermissions = ref<number[]>([])
const currentRoleId = ref<number | null>(null)
const fetchData = async () => {
loading.value = true
try {
const res: any = await request.get('/roles/page', {
params: {
page: pagination.current - 1,
size: pagination.pageSize,
sort: sortInfo.sort,
order: sortInfo.order,
keyword: searchKeyword.value || undefined
}
const res = await roleApi.getPage({
page: pagination.current - 1,
size: pagination.pageSize,
sortBy: sortInfo.sortBy,
sortOrder: sortInfo.sortOrder,
name: searchKeyword.value || undefined
})
dataSource.value = res.content
pagination.total = res.totalElements
} catch (error) {
handleApiError(error)
} finally {
loading.value = false
}
@@ -207,54 +269,142 @@ const handleSearch = () => {
}
const handleSortChange = ({ prop, order }: any) => {
sortInfo.sort = prop
sortInfo.order = order === 'ascending' ? 'asc' : 'desc'
sortInfo.sortBy = prop
sortInfo.sortOrder = order === 'ascending' ? 'asc' : 'desc'
fetchData()
}
const handleAdd = () => {
modalTitle.value = '新增角色'
Object.assign(formState, { id: null, roleName: '', roleKey: '', roleSort: 0, status: '0' })
Object.assign(formState, {
id: undefined,
name: '',
code: '',
description: '',
permissions: [],
status: 'ACTIVE'
})
modalVisible.value = true
}
const handleEdit = (row: any) => {
const handleEdit = (row: Role) => {
modalTitle.value = '编辑角色'
Object.assign(formState, row)
Object.assign(formState, {
id: row.id,
name: row.name,
code: row.code,
description: row.description,
status: row.status,
permissions: []
})
modalVisible.value = true
}
const handleDelete = async (row: any) => {
const handleDelete = async (row: Role) => {
try {
await ElMessageBox.confirm('确定要删除该角色吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
await request.delete(`/roles/${row.id}`)
await roleApi.delete(row.id)
ElMessage.success('删除成功')
fetchData()
} catch (error) {
console.error('删除角色失败:', error)
if (error !== 'cancel') {
handleApiError(error)
}
}
}
const handleModalOk = async () => {
try {
if (formState.id) {
await request.put(`/roles/${formState.id}`, formState)
const updateData: UpdateRoleRequest = {
name: formState.name,
description: formState.description,
status: formState.status as 'ACTIVE' | 'INACTIVE'
}
await roleApi.update(formState.id, updateData)
ElMessage.success('更新成功')
} else {
await request.post('/roles', formState)
const createData: CreateRoleRequest = {
name: formState.name,
code: formState.code,
description: formState.description,
permissions: formState.permissions
}
await roleApi.create(createData)
ElMessage.success('创建成功')
}
ElMessage.success('操作成功')
modalVisible.value = false
fetchData()
} catch {
ElMessage.error('操作失败')
} catch (error) {
handleApiError(error)
}
}
onMounted(() => fetchData())
const handleAssignPermissions = async (row: Role) => {
currentRoleId.value = row.id
try {
const allPermissions = await roleApi.getAllPermissions()
permissionTree.value = buildPermissionTree(allPermissions)
const rolePermissions = await roleApi.getPermissions(row.id)
selectedPermissions.value = rolePermissions.map((p: Permission) => p.id)
permissionDialogVisible.value = true
} catch (error) {
handleApiError(error)
}
}
const buildPermissionTree = (permissions: Permission[]): any[] => {
const tree: any[] = []
const resourceMap = new Map<string, Permission[]>()
permissions.forEach(p => {
if (!resourceMap.has(p.resource)) {
resourceMap.set(p.resource, [])
}
resourceMap.get(p.resource)!.push(p)
})
resourceMap.forEach((perms, resource) => {
tree.push({
id: `resource-${resource}`,
name: resource,
children: perms.map(p => ({
id: p.id,
name: p.name
}))
})
})
return tree
}
const handleAssignPermissionsOk = async () => {
if (!currentRoleId.value) return
try {
const checkedNodes = permissionTreeRef.value.getCheckedNodes()
const permissionIds = checkedNodes
.filter((node: any) => typeof node.id === 'number')
.map((node: any) => node.id)
await roleApi.assignPermissions(currentRoleId.value, permissionIds)
ElMessage.success('权限分配成功')
permissionDialogVisible.value = false
fetchData()
} catch (error) {
handleApiError(error)
}
}
onMounted(() => {
fetchData()
})
</script>
<style scoped lang="css">