diff --git a/backend/apps/monitor/views.py b/backend/apps/monitor/views.py index ca84d2b..4de3956 100644 --- a/backend/apps/monitor/views.py +++ b/backend/apps/monitor/views.py @@ -748,6 +748,8 @@ def iam_user_policies_overview_view(request, pk): 'project_name': proj.project_name, 'display_name': proj.display_name, 'project_id': proj.id, + 'monitor_enabled': proj.monitor_enabled, + 'current_spending': str(proj.current_spending), 'policies': proj_items, }) except Exception: @@ -755,6 +757,8 @@ def iam_user_policies_overview_view(request, pk): 'project_name': proj.project_name, 'display_name': proj.display_name, 'project_id': proj.id, + 'monitor_enabled': proj.monitor_enabled, + 'current_spending': str(proj.current_spending), 'policies': [], }) diff --git a/frontend/src/views/iam/UserPoliciesView.vue b/frontend/src/views/iam/UserPoliciesView.vue index af860ff..b63aeb6 100644 --- a/frontend/src/views/iam/UserPoliciesView.vue +++ b/frontend/src/views/iam/UserPoliciesView.vue @@ -1,7 +1,7 @@ - {{ overview.display_name || overview.username }} 权限总览 + {{ overview.display_name || overview.username || '...' }} 权限管理 返回子账号列表 @@ -24,7 +24,7 @@ 全局策略对所有项目生效。一般只放 Deny 策略(项目隔离),业务权限请加到项目级。 - + @@ -42,6 +42,29 @@ + + + + 关联项目 + + + + + + + + 方舟完整 + TOS完整 + 方舟只读 + + 确认添加 + + + + @@ -50,21 +73,22 @@ 项目 {{ proj.project_name }} {{ proj.display_name }} + 消费: ¥{{ Number(proj.current_spending || 0).toLocaleString() }} + toggleMonitor(proj, val)" + active-text="监测" inactive-text="" size="small" style="margin-left:12px;" /> - + 添加 + 移除项目 - - 以下权限仅在 {{ proj.project_name }} 项目范围内生效。 - - + @@ -82,7 +106,8 @@ - + @@ -101,6 +126,12 @@ const overview = ref({}) const globalPolicyToAdd = ref('') const projectPolicyToAdd = reactive({}) +// Add project +const projectToAdd = ref('') +const projectPoliciesToAttach = ref([]) +const volcProjects = ref([]) +const volcProjectsLoading = ref(false) + const policyOptions = [ { value: 'ArkFullAccess', label: 'ArkFullAccess(方舟/Seedance 完整权限)' }, { value: 'ArkExperienceAccess', label: 'ArkExperienceAccess(方舟体验权限)' }, @@ -122,6 +153,20 @@ async function loadOverview() { } } +async function loadVolcProjects() { + if (volcProjects.value.length) return + volcProjectsLoading.value = true + try { + const { data } = await api.get('/api/v1/projects/') + volcProjects.value = data + } catch (e) { + ElMessage.error('获取火山项目列表失败') + } finally { + volcProjectsLoading.value = false + } +} + +// === Global policies === async function attachGlobal() { if (!globalPolicyToAdd.value) return try { @@ -151,11 +196,50 @@ async function detachGlobal(row) { } } +// === Project management === +async function handleAddProject() { + if (!projectToAdd.value) return + try { + await api.post(`/api/v1/iam-users/${userId}/projects/add/`, { + project_name: projectToAdd.value, + policies: projectPoliciesToAttach.value, + }) + ElMessage.success(`已关联项目 ${projectToAdd.value}`) + projectToAdd.value = '' + projectPoliciesToAttach.value = [] + await loadOverview() + } catch (e) { + ElMessage.error(e.response?.data?.message || '添加失败') + } +} + +async function removeProject(proj) { + await ElMessageBox.confirm(`确定移除项目 "${proj.project_name}" 吗?权限将被回收。`, '确认移除', { type: 'warning' }) + try { + await api.delete(`/api/v1/iam-users/${userId}/projects/${proj.project_id}/delete/`) + ElMessage.success(`已移除项目 ${proj.project_name}`) + await loadOverview() + } catch (e) { + ElMessage.error(e.response?.data?.message || '移除失败') + } +} + +async function toggleMonitor(proj, val) { + try { + await api.put(`/api/v1/iam-users/${userId}/projects/${proj.project_id}/`, { + monitor_enabled: val, + }) + await loadOverview() + } catch (e) { + ElMessage.error('切换失败') + } +} + +// === Project-level policies === async function attachProject(proj) { const policyName = projectPolicyToAdd[proj.project_name] if (!policyName) return try { - // Use the project policies update endpoint const newPolicies = [...(proj.policies || []).map(p => p.name), policyName] await api.put(`/api/v1/iam-users/${userId}/projects/${proj.project_id}/policies/`, { policies: newPolicies,