feat: implement full RBAC role-based access control

Backend:
- deps.py: add require_admin, require_manager, require_labeler, require_guest_or_above
- user.py: all write endpoints require admin
- datasource.py: write/sync endpoints require admin
- metadata.py: sync endpoint requires admin
- classification.py: category/rule write requires admin; results query requires guest+ with data isolation
- project.py: GET requires manager with created_by filtering; DELETE checks ownership
- task.py: my-tasks requires labeler with assignee_id filtering; create-task requires manager
- dashboard.py: requires guest_or_above
- report.py: requires guest_or_above
- project_service: list_projects adds created_by filter; list_results adds project_ids filter

Frontend:
- stores/user.ts: add hasRole, hasAnyRole, isAdmin, isManager, isLabeler, isSuperadmin
- router/index.ts: add roles to route meta; beforeEach checks role permissions
- Layout.vue: filter menu routes by user roles
- System.vue: hide add/edit/delete buttons for non-admins
- DataSource.vue: hide add/edit/delete/sync buttons for non-admins
- Project.vue: hide add/delete buttons for non-admins
This commit is contained in:
hiderfong
2026-04-23 12:09:32 +08:00
parent 377e9cba22
commit 8b2bc84399
16 changed files with 245 additions and 59 deletions
+6 -4
View File
@@ -2,7 +2,7 @@
<div class="page-container">
<div class="page-header">
<h2 class="page-title">数据源管理</h2>
<el-button type="primary" @click="handleAdd">
<el-button v-if="userStore.isAdmin" type="primary" @click="handleAdd">
<el-icon><Plus /></el-icon>新增数据源
</el-button>
</div>
@@ -44,9 +44,9 @@
</el-table-column>
<el-table-column label="操作" width="260" fixed="right">
<template #default="{ row }">
<el-button type="primary" link size="small" @click="handleEdit(row)">编辑</el-button>
<el-button type="primary" link size="small" @click="handleSync(row)">同步元数据</el-button>
<el-button type="danger" link size="small" @click="handleDelete(row)">删除</el-button>
<el-button v-if="userStore.isAdmin" type="primary" link size="small" @click="handleEdit(row)">编辑</el-button>
<el-button v-if="userStore.isAdmin" type="primary" link size="small" @click="handleSync(row)">同步元数据</el-button>
<el-button v-if="userStore.isAdmin" type="danger" link size="small" @click="handleDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
@@ -114,9 +114,11 @@
import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus, Search } from '@element-plus/icons-vue'
import { useUserStore } from '@/stores/user'
import { getDataSources, createDataSource, updateDataSource, deleteDataSource, testConnection, syncMetadata } from '@/api/datasource'
import type { DataSourceItem, DataSourceForm } from '@/api/datasource'
const userStore = useUserStore()
const loading = ref(false)
const tableData = ref<DataSourceItem[]>([])
const page = ref(1)