feat(admin): add edit flows for all catalogs and member authentik sync
This commit is contained in:
@@ -15,7 +15,9 @@
|
||||
@submit.prevent="handleGrant"
|
||||
>
|
||||
<el-form-item label="Authentik Sub" prop="authentik_sub">
|
||||
<el-input v-model="grantForm.authentik_sub" placeholder="authentik-sub-xxx" />
|
||||
<el-select v-model="grantForm.authentik_sub" filterable allow-create default-first-option placeholder="選擇會員或輸入 sub" style="width: 100%">
|
||||
<el-option v-for="m in members" :key="m.authentik_sub" :label="`${m.display_name || m.email || '(no-name)'} (${m.authentik_sub})`" :value="m.authentik_sub" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="Email" prop="email">
|
||||
<el-input v-model="grantForm.email" placeholder="user@example.com" />
|
||||
@@ -30,16 +32,24 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="Scope ID" prop="scope_id">
|
||||
<el-input v-model="grantForm.scope_id" placeholder="company_key or site_key" />
|
||||
<el-select v-model="grantForm.scope_id" placeholder="選擇 Scope ID" filterable style="width: 100%">
|
||||
<el-option v-for="s in grantScopeOptions" :key="s.value" :label="s.label" :value="s.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="系統" prop="system">
|
||||
<el-input v-model="grantForm.system" placeholder="mkt" />
|
||||
<el-select v-model="grantForm.system" placeholder="選擇系統" filterable style="width: 100%">
|
||||
<el-option v-for="s in systems" :key="s.system_key" :label="`${s.name} (${s.system_key})`" :value="s.system_key" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="模組(選填)" prop="module">
|
||||
<el-input v-model="grantForm.module" placeholder="campaign(空值代表系統層)" clearable />
|
||||
<el-select v-model="grantForm.module" placeholder="系統層(留空) 或選模組" clearable filterable style="width: 100%">
|
||||
<el-option v-for="m in grantModuleOptions" :key="m.value" :label="m.label" :value="m.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="操作" prop="action">
|
||||
<el-input v-model="grantForm.action" placeholder="view" />
|
||||
<el-select v-model="grantForm.action" filterable allow-create default-first-option style="width: 100%">
|
||||
<el-option v-for="a in actionOptions" :key="a" :label="a" :value="a" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-alert
|
||||
@@ -83,7 +93,9 @@
|
||||
@submit.prevent="handleRevoke"
|
||||
>
|
||||
<el-form-item label="Authentik Sub" prop="authentik_sub">
|
||||
<el-input v-model="revokeForm.authentik_sub" placeholder="authentik-sub-xxx" />
|
||||
<el-select v-model="revokeForm.authentik_sub" filterable allow-create default-first-option placeholder="選擇會員或輸入 sub" style="width: 100%">
|
||||
<el-option v-for="m in members" :key="m.authentik_sub" :label="`${m.display_name || m.email || '(no-name)'} (${m.authentik_sub})`" :value="m.authentik_sub" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="Scope 類型" prop="scope_type">
|
||||
<el-select v-model="revokeForm.scope_type" placeholder="選擇 Scope 類型">
|
||||
@@ -92,16 +104,24 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="Scope ID" prop="scope_id">
|
||||
<el-input v-model="revokeForm.scope_id" placeholder="company_key or site_key" />
|
||||
<el-select v-model="revokeForm.scope_id" placeholder="選擇 Scope ID" filterable style="width: 100%">
|
||||
<el-option v-for="s in revokeScopeOptions" :key="s.value" :label="s.label" :value="s.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="系統" prop="system">
|
||||
<el-input v-model="revokeForm.system" placeholder="mkt" />
|
||||
<el-select v-model="revokeForm.system" placeholder="選擇系統" filterable style="width: 100%">
|
||||
<el-option v-for="s in systems" :key="s.system_key" :label="`${s.name} (${s.system_key})`" :value="s.system_key" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="模組(選填)" prop="module">
|
||||
<el-input v-model="revokeForm.module" placeholder="campaign(空值代表系統層)" clearable />
|
||||
<el-select v-model="revokeForm.module" placeholder="系統層(留空) 或選模組" clearable filterable style="width: 100%">
|
||||
<el-option v-for="m in revokeModuleOptions" :key="m.value" :label="m.label" :value="m.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="操作" prop="action">
|
||||
<el-input v-model="revokeForm.action" placeholder="view" />
|
||||
<el-select v-model="revokeForm.action" filterable allow-create default-first-option style="width: 100%">
|
||||
<el-option v-for="a in actionOptions" :key="a" :label="a" :value="a" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-alert
|
||||
@@ -138,13 +158,24 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { ref, reactive, onMounted, computed, watch } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { usePermissionStore } from '@/stores/permission'
|
||||
import { getSystems } from '@/api/systems'
|
||||
import { getModules } from '@/api/modules'
|
||||
import { getCompanies } from '@/api/companies'
|
||||
import { getSites } from '@/api/sites'
|
||||
import { getMembers } from '@/api/members'
|
||||
|
||||
const permissionStore = usePermissionStore()
|
||||
|
||||
const activeTab = ref('grant')
|
||||
const systems = ref([])
|
||||
const modules = ref([])
|
||||
const companies = ref([])
|
||||
const sites = ref([])
|
||||
const members = ref([])
|
||||
const actionOptions = ['view', 'edit', 'manage', 'admin']
|
||||
|
||||
// Grant
|
||||
const grantFormRef = ref()
|
||||
@@ -163,6 +194,26 @@ const grantForm = reactive({
|
||||
action: ''
|
||||
})
|
||||
|
||||
const grantModuleOptions = computed(() => {
|
||||
if (!grantForm.system) return []
|
||||
return modules.value
|
||||
.filter(m => m.system_key === grantForm.system && !m.module_key.endsWith('.__system__'))
|
||||
.map(m => ({
|
||||
value: m.module_key.split('.', 2)[1] || m.module_key,
|
||||
label: `${m.name} (${m.module_key})`
|
||||
}))
|
||||
})
|
||||
|
||||
const grantScopeOptions = computed(() => {
|
||||
if (grantForm.scope_type === 'company') {
|
||||
return companies.value.map(c => ({ value: c.company_key, label: `${c.name} (${c.company_key})` }))
|
||||
}
|
||||
if (grantForm.scope_type === 'site') {
|
||||
return sites.value.map(s => ({ value: s.site_key, label: `${s.name} (${s.site_key})` }))
|
||||
}
|
||||
return []
|
||||
})
|
||||
|
||||
const required = { required: true, message: '必填', trigger: 'blur' }
|
||||
const grantRules = {
|
||||
authentik_sub: [required],
|
||||
@@ -212,6 +263,26 @@ const revokeForm = reactive({
|
||||
action: ''
|
||||
})
|
||||
|
||||
const revokeModuleOptions = computed(() => {
|
||||
if (!revokeForm.system) return []
|
||||
return modules.value
|
||||
.filter(m => m.system_key === revokeForm.system && !m.module_key.endsWith('.__system__'))
|
||||
.map(m => ({
|
||||
value: m.module_key.split('.', 2)[1] || m.module_key,
|
||||
label: `${m.name} (${m.module_key})`
|
||||
}))
|
||||
})
|
||||
|
||||
const revokeScopeOptions = computed(() => {
|
||||
if (revokeForm.scope_type === 'company') {
|
||||
return companies.value.map(c => ({ value: c.company_key, label: `${c.name} (${c.company_key})` }))
|
||||
}
|
||||
if (revokeForm.scope_type === 'site') {
|
||||
return sites.value.map(s => ({ value: s.site_key, label: `${s.name} (${s.site_key})` }))
|
||||
}
|
||||
return []
|
||||
})
|
||||
|
||||
const revokeRules = {
|
||||
authentik_sub: [required],
|
||||
scope_type: [required],
|
||||
@@ -265,4 +336,33 @@ function formatAdminError(err) {
|
||||
if (status === 503) return '後端設定不完整,請聯絡管理員'
|
||||
return '操作失敗,請稍後再試'
|
||||
}
|
||||
|
||||
async function loadCatalogs() {
|
||||
const [systemsRes, modulesRes, companiesRes, sitesRes, membersRes] = await Promise.all([
|
||||
getSystems(),
|
||||
getModules(),
|
||||
getCompanies(),
|
||||
getSites(),
|
||||
getMembers()
|
||||
])
|
||||
systems.value = systemsRes.data?.items || []
|
||||
modules.value = modulesRes.data?.items || []
|
||||
companies.value = companiesRes.data?.items || []
|
||||
sites.value = sitesRes.data?.items || []
|
||||
members.value = membersRes.data?.items || []
|
||||
}
|
||||
|
||||
watch(() => grantForm.scope_type, () => { grantForm.scope_id = '' })
|
||||
watch(() => grantForm.system, () => { grantForm.module = '' })
|
||||
watch(() => revokeForm.scope_type, () => { revokeForm.scope_id = '' })
|
||||
watch(() => revokeForm.system, () => { revokeForm.module = '' })
|
||||
|
||||
watch(() => grantForm.authentik_sub, (sub) => {
|
||||
const user = members.value.find(m => m.authentik_sub === sub)
|
||||
if (!user) return
|
||||
grantForm.email = user.email || ''
|
||||
grantForm.display_name = user.display_name || ''
|
||||
})
|
||||
|
||||
onMounted(loadCatalogs)
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user