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 <el-table-column
prop="id" prop="id"
label="ID" label="ID"
width="80"
sortable="custom" sortable="custom"
/> />
<el-table-column <el-table-column
prop="roleName" prop="name"
label="角色名称" label="角色名称"
sortable="custom" sortable="custom"
/> />
<el-table-column <el-table-column
prop="roleKey" prop="code"
label="角色标识" label="角色标识"
sortable="custom" sortable="custom"
/> />
<el-table-column <el-table-column
prop="roleSort" prop="description"
label="排序" label="描述"
sortable="custom"
/> />
<el-table-column label="状态"> <el-table-column
label="状态"
width="100"
>
<template #default="{ row }"> <template #default="{ row }">
<el-tag :type="row.status === '0' ? 'success' : 'danger'"> <el-tag :type="row.status === 'ACTIVE' ? 'success' : 'danger'">
{{ row.status === '0' ? '正常' : '禁用' }} {{ row.status === 'ACTIVE' ? '正常' : '禁用' }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
@@ -71,7 +74,7 @@
/> />
<el-table-column <el-table-column
label="操作" label="操作"
width="200" width="250"
> >
<template #default="{ row }"> <template #default="{ row }">
<el-button <el-button
@@ -81,6 +84,13 @@
> >
编辑 编辑
</el-button> </el-button>
<el-button
type="warning"
link
@click="handleAssignPermissions(row)"
>
分配权限
</el-button>
<el-button <el-button
type="danger" type="danger"
link link
@@ -112,23 +122,35 @@
:model="formState" :model="formState"
label-width="80px" label-width="80px"
> >
<el-form-item label="角色名称"> <el-form-item
<el-input v-model="formState.roleName" /> label="角色名称"
required
>
<el-input v-model="formState.name" />
</el-form-item> </el-form-item>
<el-form-item label="角色标识"> <el-form-item
<el-input v-model="formState.roleKey" /> label="角色标识"
required
>
<el-input
v-model="formState.code"
:disabled="!!formState.id"
/>
</el-form-item> </el-form-item>
<el-form-item label="排序"> <el-form-item label="描述">
<el-input-number v-model="formState.roleSort" /> <el-input
v-model="formState.description"
type="textarea"
/>
</el-form-item> </el-form-item>
<el-form-item label="状态"> <el-form-item label="状态">
<el-select v-model="formState.status"> <el-select v-model="formState.status">
<el-option <el-option
value="0" value="ACTIVE"
label="正常" label="正常"
/> />
<el-option <el-option
value="1" value="INACTIVE"
label="禁用" label="禁用"
/> />
</el-select> </el-select>
@@ -146,6 +168,33 @@
</el-button> </el-button>
</template> </template>
</el-dialog> </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> </div>
</template> </template>
@@ -153,10 +202,11 @@
import { ref, reactive, onMounted } from 'vue' import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { Search } from '@element-plus/icons-vue' 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 loading = ref(false)
const dataSource = ref([]) const dataSource = ref<Role[]>([])
const searchKeyword = ref('') const searchKeyword = ref('')
const pagination = reactive({ const pagination = reactive({
current: 1, current: 1,
@@ -165,28 +215,40 @@ const pagination = reactive({
}) })
const sortInfo = reactive({ const sortInfo = reactive({
sort: 'id', sortBy: 'id',
order: 'asc' sortOrder: 'asc' as 'asc' | 'desc'
}) })
const modalVisible = ref(false) const modalVisible = ref(false)
const modalTitle = ref('') 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 () => { const fetchData = async () => {
loading.value = true loading.value = true
try { try {
const res: any = await request.get('/roles/page', { const res = await roleApi.getPage({
params: {
page: pagination.current - 1, page: pagination.current - 1,
size: pagination.pageSize, size: pagination.pageSize,
sort: sortInfo.sort, sortBy: sortInfo.sortBy,
order: sortInfo.order, sortOrder: sortInfo.sortOrder,
keyword: searchKeyword.value || undefined name: searchKeyword.value || undefined
}
}) })
dataSource.value = res.content dataSource.value = res.content
pagination.total = res.totalElements pagination.total = res.totalElements
} catch (error) {
handleApiError(error)
} finally { } finally {
loading.value = false loading.value = false
} }
@@ -207,54 +269,142 @@ const handleSearch = () => {
} }
const handleSortChange = ({ prop, order }: any) => { const handleSortChange = ({ prop, order }: any) => {
sortInfo.sort = prop sortInfo.sortBy = prop
sortInfo.order = order === 'ascending' ? 'asc' : 'desc' sortInfo.sortOrder = order === 'ascending' ? 'asc' : 'desc'
fetchData() fetchData()
} }
const handleAdd = () => { const handleAdd = () => {
modalTitle.value = '新增角色' 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 modalVisible.value = true
} }
const handleEdit = (row: any) => { const handleEdit = (row: Role) => {
modalTitle.value = '编辑角色' 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 modalVisible.value = true
} }
const handleDelete = async (row: any) => { const handleDelete = async (row: Role) => {
try { try {
await ElMessageBox.confirm('确定要删除该角色吗?', '提示', { await ElMessageBox.confirm('确定要删除该角色吗?', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}) })
await request.delete(`/roles/${row.id}`) await roleApi.delete(row.id)
ElMessage.success('删除成功') ElMessage.success('删除成功')
fetchData() fetchData()
} catch (error) { } catch (error) {
console.error('删除角色失败:', error) if (error !== 'cancel') {
handleApiError(error)
}
} }
} }
const handleModalOk = async () => { const handleModalOk = async () => {
try { try {
if (formState.id) { if (formState.id) {
await request.put(`/roles/${formState.id}`, formState) const updateData: UpdateRoleRequest = {
} else { name: formState.name,
await request.post('/roles', formState) description: formState.description,
status: formState.status as 'ACTIVE' | 'INACTIVE'
}
await roleApi.update(formState.id, updateData)
ElMessage.success('更新成功')
} else {
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 modalVisible.value = false
fetchData() fetchData()
} catch { } catch (error) {
ElMessage.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> </script>
<style scoped lang="css"> <style scoped lang="css">