refactor: remove old project/policy dialogs from IAMUserList
All project management and policy operations now handled in the unified UserPoliciesView page. Removed unused dialogs, variables, and functions from IAMUserList. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
dacc521c1c
commit
c4c6a03f61
@ -53,7 +53,7 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="项目" min-width="80" align="center">
|
<el-table-column label="项目" min-width="80" align="center">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button link type="primary" size="small" @click="openProjectsDialog(row)">
|
<el-button link type="primary" size="small" @click="$router.push(`/iam-users/${row.id}/policies`)">
|
||||||
{{ row.monitored_project_count || 0 }} / {{ (row.projects || []).length }}
|
{{ row.monitored_project_count || 0 }} / {{ (row.projects || []).length }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
@ -76,7 +76,6 @@
|
|||||||
</el-button>
|
</el-button>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
<el-dropdown-item @click="openProjectsDialog(row)">项目管理</el-dropdown-item>
|
|
||||||
<el-dropdown-item @click="openConfig(row)">监控配置</el-dropdown-item>
|
<el-dropdown-item @click="openConfig(row)">监控配置</el-dropdown-item>
|
||||||
<el-dropdown-item @click="openEditProfile(row)">编辑信息</el-dropdown-item>
|
<el-dropdown-item @click="openEditProfile(row)">编辑信息</el-dropdown-item>
|
||||||
<el-dropdown-item @click="toggleVolcLogin(row)">
|
<el-dropdown-item @click="toggleVolcLogin(row)">
|
||||||
@ -163,87 +162,6 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<!-- Projects Dialog -->
|
|
||||||
<el-dialog v-model="projectsDialogVisible" :title="`${projectsUser?.username} 关联项目`" width="90%" style="max-width: 900px;">
|
|
||||||
<div style="margin-bottom:12px; display:flex; gap:8px; align-items:center;">
|
|
||||||
<el-select v-model="projectToAdd" placeholder="选择火山项目" filterable style="flex:1;"
|
|
||||||
:loading="volcProjectsLoading">
|
|
||||||
<el-option v-for="p in volcProjects" :key="p.name" :label="p.display_name || p.name" :value="p.name" />
|
|
||||||
</el-select>
|
|
||||||
<el-button @click="loadVolcProjects" :loading="volcProjectsLoading" text>
|
|
||||||
<el-icon><Refresh /></el-icon>
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
<div v-if="projectToAdd" style="margin-bottom:12px;">
|
|
||||||
<div style="margin-bottom:4px; font-size:13px; color:#606266;">授权策略(可多选,不选则仅加入监测不授权):</div>
|
|
||||||
<el-checkbox-group v-model="projectPoliciesToAttach">
|
|
||||||
<el-checkbox label="ArkFullAccess">方舟/Seedance 完整权限</el-checkbox>
|
|
||||||
<el-checkbox label="ArkExperienceAccess">方舟体验权限(API Key 管理需要)</el-checkbox>
|
|
||||||
<el-checkbox label="ArkReadOnlyAccess">方舟只读</el-checkbox>
|
|
||||||
<el-checkbox label="TOSFullAccess">对象存储完整权限</el-checkbox>
|
|
||||||
<el-checkbox label="TOSReadOnlyAccess">对象存储只读</el-checkbox>
|
|
||||||
<el-checkbox label="AccessKeySelfManageAccess">自管理密钥</el-checkbox>
|
|
||||||
</el-checkbox-group>
|
|
||||||
<el-button type="primary" @click="handleAddProject" style="margin-top:8px;">确认添加</el-button>
|
|
||||||
</div>
|
|
||||||
<div style="margin-bottom:12px;">
|
|
||||||
<el-button size="small" @click="handleToggleAll(true)">全部开启监测</el-button>
|
|
||||||
<el-button size="small" @click="handleToggleAll(false)">全部关闭监测</el-button>
|
|
||||||
</div>
|
|
||||||
<el-table :data="userProjects" stripe v-loading="projectsDialogLoading" empty-text="暂无关联项目">
|
|
||||||
<el-table-column prop="project_name" label="项目名" min-width="160" />
|
|
||||||
<el-table-column prop="display_name" label="显示名" min-width="120" />
|
|
||||||
<el-table-column label="消费" min-width="100" align="right">
|
|
||||||
<template #default="{ row }">
|
|
||||||
<span style="color:#e6a23c;">¥{{ Number(row.current_spending).toLocaleString() }}</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="已授权策略" min-width="180">
|
|
||||||
<template #default="{ row }">
|
|
||||||
<el-tag v-for="p in (row.attached_policies || [])" :key="p" size="small"
|
|
||||||
style="margin:1px 2px;">{{ p }}</el-tag>
|
|
||||||
<span v-if="!(row.attached_policies || []).length" style="color:#999;font-size:12px;">无</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="监测" min-width="70" align="center">
|
|
||||||
<template #default="{ row }">
|
|
||||||
<el-switch :model-value="row.monitor_enabled" @change="val => handleToggleProject(row, val)" />
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="操作" width="140" align="center">
|
|
||||||
<template #default="{ row }">
|
|
||||||
<el-button size="small" type="primary" text @click="openProjectPolicies(row)">授权</el-button>
|
|
||||||
<el-button size="small" type="danger" text @click="handleRemoveProject(row)">移除</el-button>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
</el-dialog>
|
|
||||||
|
|
||||||
<!-- Project Policies Dialog -->
|
|
||||||
<el-dialog v-model="projectPolicyVisible"
|
|
||||||
:title="`${projectPolicyProject?.project_name} 项目级授权`"
|
|
||||||
width="90%" style="max-width: 550px;">
|
|
||||||
<el-alert type="info" :closable="false" style="margin-bottom:12px;">
|
|
||||||
<template #title>
|
|
||||||
以下权限仅在 <strong>{{ projectPolicyProject?.project_name }}</strong> 项目范围内生效,不影响其他项目。
|
|
||||||
</template>
|
|
||||||
</el-alert>
|
|
||||||
<el-checkbox-group v-model="projectPolicySelected">
|
|
||||||
<div style="display:flex; flex-direction:column; gap:8px;">
|
|
||||||
<el-checkbox label="ArkFullAccess">方舟/Seedance 完整权限</el-checkbox>
|
|
||||||
<el-checkbox label="ArkExperienceAccess">方舟体验权限(API Key 管理需要)</el-checkbox>
|
|
||||||
<el-checkbox label="ArkReadOnlyAccess">方舟只读</el-checkbox>
|
|
||||||
<el-checkbox label="TOSFullAccess">对象存储完整权限</el-checkbox>
|
|
||||||
<el-checkbox label="TOSReadOnlyAccess">对象存储只读</el-checkbox>
|
|
||||||
<el-checkbox label="AccessKeySelfManageAccess">自管理密钥</el-checkbox>
|
|
||||||
</div>
|
|
||||||
</el-checkbox-group>
|
|
||||||
<template #footer>
|
|
||||||
<el-button @click="projectPolicyVisible = false">取消</el-button>
|
|
||||||
<el-button type="primary" @click="handleSaveProjectPolicies" :loading="projectPolicySaving">保存</el-button>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
|
|
||||||
<!-- Set Login Password Dialog -->
|
<!-- Set Login Password Dialog -->
|
||||||
<el-dialog v-model="loginPwdVisible" :title="`设置 ${loginPwdUser?.username} 的 AirGate 登录密码`"
|
<el-dialog v-model="loginPwdVisible" :title="`设置 ${loginPwdUser?.username} 的 AirGate 登录密码`"
|
||||||
width="90%" style="max-width: 450px;">
|
width="90%" style="max-width: 450px;">
|
||||||
@ -284,40 +202,6 @@
|
|||||||
</el-table>
|
</el-table>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<!-- Policies Dialog (Global) -->
|
|
||||||
<el-dialog v-model="policiesVisible" :title="`${policiesUser?.username} 全局权限策略`" width="90%" style="max-width: 850px;">
|
|
||||||
<el-alert type="info" :closable="false" style="margin-bottom:12px;">
|
|
||||||
<template #title>
|
|
||||||
<strong>全局策略</strong>对所有项目生效。如需限定到某个项目,请在「项目管理 → 授权」中设置项目级策略。
|
|
||||||
</template>
|
|
||||||
</el-alert>
|
|
||||||
<div style="margin-bottom:12px; display:flex; gap:8px;">
|
|
||||||
<el-select v-model="policyToAttach" placeholder="选择要附加的策略" filterable style="flex:1;">
|
|
||||||
<el-option-group label="常用策略">
|
|
||||||
<el-option v-for="opt in globalPolicyOptions" :key="opt.value"
|
|
||||||
:value="opt.value" :label="opt.label"
|
|
||||||
:disabled="policies.some(p => p.PolicyName === opt.value)" />
|
|
||||||
</el-option-group>
|
|
||||||
</el-select>
|
|
||||||
<el-button type="primary" @click="handleAttachPolicy" :disabled="!policyToAttach">附加</el-button>
|
|
||||||
</div>
|
|
||||||
<el-table :data="policies" stripe v-loading="policiesLoading" empty-text="暂无策略">
|
|
||||||
<el-table-column prop="PolicyName" label="策略名" min-width="200" />
|
|
||||||
<el-table-column prop="PolicyType" label="类型" width="80">
|
|
||||||
<template #default="{ row }">
|
|
||||||
<el-tag :type="row.PolicyType === 'Custom' ? 'warning' : 'info'" size="small">
|
|
||||||
{{ row.PolicyType === 'Custom' ? '自定义' : '系统' }}
|
|
||||||
</el-tag>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column prop="Description" label="说明" min-width="200" />
|
|
||||||
<el-table-column label="操作" width="80">
|
|
||||||
<template #default="{ row }">
|
|
||||||
<el-button size="small" type="danger" text @click="handleDetachPolicy(row)">移除</el-button>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
</el-dialog>
|
|
||||||
|
|
||||||
<!-- Create User Dialog -->
|
<!-- Create User Dialog -->
|
||||||
<el-dialog v-model="showCreate" title="创建子账号" width="90%" style="max-width: 580px;">
|
<el-dialog v-model="showCreate" title="创建子账号" width="90%" style="max-width: 580px;">
|
||||||
@ -488,16 +372,6 @@ async function handleEnable(row) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global policy options
|
|
||||||
const globalPolicyOptions = [
|
|
||||||
{ value: 'ArkFullAccess', label: 'ArkFullAccess(方舟/Seedance 完整权限)' },
|
|
||||||
{ value: 'ArkExperienceAccess', label: 'ArkExperienceAccess(方舟体验权限)' },
|
|
||||||
{ value: 'ArkReadOnlyAccess', label: 'ArkReadOnlyAccess(方舟只读)' },
|
|
||||||
{ value: 'TOSFullAccess', label: 'TOSFullAccess(对象存储完整权限)' },
|
|
||||||
{ value: 'TOSReadOnlyAccess', label: 'TOSReadOnlyAccess(对象存储只读)' },
|
|
||||||
{ value: 'AccessKeySelfManageAccess', label: 'AccessKeySelfManageAccess(自管理密钥)' },
|
|
||||||
]
|
|
||||||
|
|
||||||
// Toggle Volcengine console login
|
// Toggle Volcengine console login
|
||||||
async function toggleVolcLogin(row) {
|
async function toggleVolcLogin(row) {
|
||||||
const action = row.volc_login_allowed ? '关闭' : '开启'
|
const action = row.volc_login_allowed ? '关闭' : '开启'
|
||||||
@ -547,22 +421,9 @@ async function handleEditProfile() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Policies
|
// (Policies dialog removed - now in UserPoliciesView)
|
||||||
const policiesVisible = ref(false)
|
|
||||||
const policiesUser = ref(null)
|
|
||||||
const policies = ref([])
|
|
||||||
const policiesLoading = ref(false)
|
|
||||||
const policyToAttach = ref('')
|
|
||||||
|
|
||||||
// Projects dialog
|
// (Projects dialog removed - now in UserPoliciesView)
|
||||||
const projectsDialogVisible = ref(false)
|
|
||||||
const projectsUser = ref(null)
|
|
||||||
const userProjects = ref([])
|
|
||||||
const projectsDialogLoading = ref(false)
|
|
||||||
const projectToAdd = ref('')
|
|
||||||
const projectPoliciesToAttach = ref([])
|
|
||||||
const volcProjects = ref([])
|
|
||||||
const volcProjectsLoading = ref(false)
|
|
||||||
|
|
||||||
// --- Allocate ---
|
// --- Allocate ---
|
||||||
const maxDeduct = computed(() => {
|
const maxDeduct = computed(() => {
|
||||||
@ -618,126 +479,6 @@ function openConfig(row) {
|
|||||||
configVisible.value = true
|
configVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Projects Dialog ---
|
|
||||||
async function loadVolcProjects() {
|
|
||||||
volcProjectsLoading.value = true
|
|
||||||
try {
|
|
||||||
const { data } = await api.get('/api/v1/projects/')
|
|
||||||
volcProjects.value = data
|
|
||||||
} catch (e) {
|
|
||||||
ElMessage.error(e.response?.data?.message || '获取火山项目列表失败')
|
|
||||||
} finally {
|
|
||||||
volcProjectsLoading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function openProjectsDialog(row) {
|
|
||||||
projectsUser.value = row
|
|
||||||
projectsDialogVisible.value = true
|
|
||||||
projectToAdd.value = ''
|
|
||||||
await loadUserProjects(row.id)
|
|
||||||
if (volcProjects.value.length === 0) loadVolcProjects()
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadUserProjects(userId) {
|
|
||||||
projectsDialogLoading.value = true
|
|
||||||
try {
|
|
||||||
const { data } = await api.get(`/api/v1/iam-users/${userId}/projects/`)
|
|
||||||
userProjects.value = data
|
|
||||||
} catch (e) {
|
|
||||||
ElMessage.error('获取项目列表失败')
|
|
||||||
userProjects.value = []
|
|
||||||
} finally {
|
|
||||||
projectsDialogLoading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleAddProject() {
|
|
||||||
if (!projectToAdd.value) return
|
|
||||||
try {
|
|
||||||
const { data } = await api.post(`/api/v1/iam-users/${projectsUser.value.id}/projects/add/`, {
|
|
||||||
project_name: projectToAdd.value,
|
|
||||||
policies: projectPoliciesToAttach.value,
|
|
||||||
})
|
|
||||||
const policyMsg = data.attached_policies?.length
|
|
||||||
? `,已授权 ${data.attached_policies.length} 个策略`
|
|
||||||
: ''
|
|
||||||
ElMessage.success(`已添加${policyMsg}`)
|
|
||||||
projectToAdd.value = ''
|
|
||||||
projectPoliciesToAttach.value = []
|
|
||||||
await loadUserProjects(projectsUser.value.id)
|
|
||||||
await loadUsers()
|
|
||||||
} catch (e) {
|
|
||||||
ElMessage.error(e.response?.data?.message || '添加失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleToggleProject(row, val) {
|
|
||||||
try {
|
|
||||||
await api.put(`/api/v1/iam-users/${projectsUser.value.id}/projects/${row.id}/`, {
|
|
||||||
monitor_enabled: val,
|
|
||||||
})
|
|
||||||
await loadUserProjects(projectsUser.value.id)
|
|
||||||
await loadUsers()
|
|
||||||
} catch (e) {
|
|
||||||
ElMessage.error('切换失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// === Project Policies ===
|
|
||||||
const projectPolicyVisible = ref(false)
|
|
||||||
const projectPolicyProject = ref(null)
|
|
||||||
const projectPolicySelected = ref([])
|
|
||||||
const projectPolicySaving = ref(false)
|
|
||||||
|
|
||||||
function openProjectPolicies(row) {
|
|
||||||
projectPolicyProject.value = row
|
|
||||||
projectPolicySelected.value = [...(row.attached_policies || [])]
|
|
||||||
projectPolicyVisible.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleSaveProjectPolicies() {
|
|
||||||
projectPolicySaving.value = true
|
|
||||||
try {
|
|
||||||
const { data } = await api.put(
|
|
||||||
`/api/v1/iam-users/${projectsUser.value.id}/projects/${projectPolicyProject.value.id}/policies/`,
|
|
||||||
{ policies: projectPolicySelected.value }
|
|
||||||
)
|
|
||||||
ElMessage.success(data.message || '已更新')
|
|
||||||
projectPolicyVisible.value = false
|
|
||||||
await loadUserProjects(projectsUser.value.id)
|
|
||||||
} catch (e) {
|
|
||||||
ElMessage.error(e.response?.data?.message || '更新失败')
|
|
||||||
} finally {
|
|
||||||
projectPolicySaving.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleRemoveProject(row) {
|
|
||||||
await ElMessageBox.confirm(`确定移除项目 "${row.project_name}" 吗?`, '确认', { type: 'warning' })
|
|
||||||
try {
|
|
||||||
await api.delete(`/api/v1/iam-users/${projectsUser.value.id}/projects/${row.id}/delete/`)
|
|
||||||
ElMessage.success('已移除')
|
|
||||||
await loadUserProjects(projectsUser.value.id)
|
|
||||||
await loadUsers()
|
|
||||||
} catch (e) {
|
|
||||||
ElMessage.error('移除失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleToggleAll(enable) {
|
|
||||||
try {
|
|
||||||
const { data } = await api.post(`/api/v1/iam-users/${projectsUser.value.id}/projects/toggle-all/`, {
|
|
||||||
monitor_enabled: enable,
|
|
||||||
})
|
|
||||||
ElMessage.success(data.message)
|
|
||||||
await loadUserProjects(projectsUser.value.id)
|
|
||||||
await loadUsers()
|
|
||||||
} catch (e) {
|
|
||||||
ElMessage.error('操作失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function addStep() {
|
function addStep() {
|
||||||
if (!newStep.value || newStep.value < 1 || newStep.value > 99) {
|
if (!newStep.value || newStep.value < 1 || newStep.value > 99) {
|
||||||
ElMessage.warning('请输入 1-99 之间的百分比')
|
ElMessage.warning('请输入 1-99 之间的百分比')
|
||||||
@ -822,52 +563,6 @@ async function openQuotaHistory(row) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Policies ---
|
|
||||||
async function openPolicies(row) {
|
|
||||||
policiesUser.value = row
|
|
||||||
policiesVisible.value = true
|
|
||||||
policiesLoading.value = true
|
|
||||||
policyToAttach.value = ''
|
|
||||||
try {
|
|
||||||
const { data } = await api.get(`/api/v1/iam-users/${row.id}/policies/`)
|
|
||||||
policies.value = data.policies || []
|
|
||||||
} catch (e) {
|
|
||||||
ElMessage.error(e.response?.data?.message || '获取权限失败')
|
|
||||||
policies.value = []
|
|
||||||
} finally {
|
|
||||||
policiesLoading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleAttachPolicy() {
|
|
||||||
if (!policyToAttach.value) return
|
|
||||||
try {
|
|
||||||
await api.post(`/api/v1/iam-users/${policiesUser.value.id}/policies/attach/`, {
|
|
||||||
policy_name: policyToAttach.value,
|
|
||||||
policy_type: 'System',
|
|
||||||
})
|
|
||||||
ElMessage.success(`已附加 ${policyToAttach.value}`)
|
|
||||||
policyToAttach.value = ''
|
|
||||||
await openPolicies(policiesUser.value)
|
|
||||||
} catch (e) {
|
|
||||||
ElMessage.error(e.response?.data?.message || '附加失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleDetachPolicy(row) {
|
|
||||||
await ElMessageBox.confirm(`确定移除策略 "${row.PolicyName}" 吗?`, '确认移除', { type: 'warning' })
|
|
||||||
try {
|
|
||||||
await api.post(`/api/v1/iam-users/${policiesUser.value.id}/policies/detach/`, {
|
|
||||||
policy_name: row.PolicyName,
|
|
||||||
policy_type: row.PolicyType,
|
|
||||||
})
|
|
||||||
ElMessage.success(`已移除 ${row.PolicyName}`)
|
|
||||||
await openPolicies(policiesUser.value)
|
|
||||||
} catch (e) {
|
|
||||||
ElMessage.error(e.response?.data?.message || '移除失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Create User ---
|
// --- Create User ---
|
||||||
async function handleCreate() {
|
async function handleCreate() {
|
||||||
if (!createForm.value.username) {
|
if (!createForm.value.username) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user