feat(flow): unify member-group-permission admin workflow and docs

This commit is contained in:
Chris
2026-03-30 03:54:22 +08:00
parent 31fff92e19
commit f884f1043d
17 changed files with 576 additions and 130 deletions

View File

@@ -154,6 +154,40 @@
</el-form>
</el-tab-pane>
</el-tabs>
<el-card class="mt-6 shadow-sm">
<template #header>
<div class="flex items-center justify-between gap-3">
<span class="font-medium text-gray-700">已授權列表直接授權</span>
<div class="flex items-center gap-2">
<el-input v-model="listFilters.keyword" placeholder="搜尋 email/sub/module/action" clearable style="width: 280px" @keyup.enter="loadDirectPermissionList" />
<el-select v-model="listFilters.scope_type" clearable placeholder="Scope" style="width: 140px">
<el-option label="Company" value="company" />
<el-option label="Site" value="site" />
</el-select>
<el-button :loading="listLoading" @click="loadDirectPermissionList">查詢</el-button>
</div>
</div>
</template>
<el-table :data="directPermissions" stripe border class="w-full" v-loading="listLoading">
<template #empty><el-empty description="目前沒有直接授權資料" /></template>
<el-table-column prop="display_name" label="名稱" min-width="140" />
<el-table-column prop="email" label="Email" min-width="200" />
<el-table-column prop="authentik_sub" label="Sub" min-width="200" />
<el-table-column prop="scope_type" label="Scope" width="90" />
<el-table-column prop="scope_id" label="Scope ID" min-width="120" />
<el-table-column prop="system" label="系統" width="100" />
<el-table-column prop="module" label="模組" width="130" />
<el-table-column prop="action" label="操作" width="100" />
<el-table-column prop="created_at" label="建立時間" min-width="180" />
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }">
<el-button type="danger" size="small" @click="handleRevokeByRow(row)" :loading="revokeRowLoadingId === row.permission_id">撤銷</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
@@ -166,6 +200,7 @@ import { getModules } from '@/api/modules'
import { getCompanies } from '@/api/companies'
import { getSites } from '@/api/sites'
import { getMembers } from '@/api/members'
import { listDirectPermissions, revokeDirectPermissionById } from '@/api/permission-admin'
const permissionStore = usePermissionStore()
@@ -176,6 +211,10 @@ const companies = ref([])
const sites = ref([])
const members = ref([])
const actionOptions = ['view', 'edit', 'manage', 'admin']
const listFilters = reactive({ keyword: '', scope_type: '' })
const listLoading = ref(false)
const directPermissions = ref([])
const revokeRowLoadingId = ref('')
// Grant
const grantFormRef = ref()
@@ -237,6 +276,7 @@ async function handleGrant() {
const result = await permissionStore.grant({ ...grantForm })
grantSuccess.value = `授權成功ID: ${result.permission_id}`
ElMessage.success('Grant 成功')
await loadDirectPermissionList()
} catch (err) {
grantError.value = formatAdminError(err)
} finally {
@@ -305,6 +345,7 @@ async function handleRevoke() {
const result = await permissionStore.revoke({ ...revokeForm })
revokeSuccess.value = `撤銷成功(共刪除 ${result.deleted} 筆)`
ElMessage.success('Revoke 成功')
await loadDirectPermissionList()
} catch (err) {
revokeError.value = formatAdminError(err)
} finally {
@@ -356,6 +397,39 @@ async function loadCatalogs() {
members.value = membersRes.data?.items || []
}
async function loadDirectPermissionList() {
listLoading.value = true
try {
const res = await listDirectPermissions({
keyword: listFilters.keyword || undefined,
scope_type: listFilters.scope_type || undefined,
limit: 200,
offset: 0
})
directPermissions.value = (res.data?.items || []).map(row => ({
...row,
created_at: row.created_at ? new Date(row.created_at).toLocaleString() : ''
}))
} catch (err) {
ElMessage.error('載入權限列表失敗')
} finally {
listLoading.value = false
}
}
async function handleRevokeByRow(row) {
revokeRowLoadingId.value = row.permission_id
try {
await revokeDirectPermissionById(row.permission_id)
ElMessage.success('已撤銷該筆授權')
await loadDirectPermissionList()
} catch (err) {
ElMessage.error('撤銷失敗')
} finally {
revokeRowLoadingId.value = ''
}
}
watch(() => grantForm.scope_type, () => { grantForm.scope_id = '' })
watch(() => grantForm.system, () => { grantForm.module = '' })
watch(() => revokeForm.scope_type, () => { revokeForm.scope_id = '' })
@@ -368,5 +442,7 @@ watch(() => grantForm.authentik_sub, (sub) => {
grantForm.display_name = user.display_name || ''
})
onMounted(loadCatalogs)
onMounted(async () => {
await Promise.all([loadCatalogs(), loadDirectPermissionList()])
})
</script>