80 lines
2.4 KiB
Vue
80 lines
2.4 KiB
Vue
<script setup lang="ts">
|
|
import { computed, ref, watch } from 'vue'
|
|
import { ElMessage } from 'element-plus'
|
|
import { getAcl, setAcl, type AclEntry } from '@/api/modules/acl'
|
|
|
|
const props = defineProps<{
|
|
modelValue: boolean
|
|
resourceType: string
|
|
resourceId: string
|
|
}>()
|
|
const emit = defineEmits<{ 'update:modelValue': [boolean] }>()
|
|
|
|
const visible = computed({
|
|
get: () => props.modelValue,
|
|
set: (v) => emit('update:modelValue', v),
|
|
})
|
|
const entries = ref<AclEntry[]>([])
|
|
const loading = ref(false)
|
|
const ALL_PERMS = ['read', 'write', 'execute', 'download', 'delete', 'share']
|
|
|
|
async function load() {
|
|
loading.value = true
|
|
try {
|
|
entries.value = await getAcl(props.resourceType, props.resourceId)
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
watch(visible, (v) => { if (v) load() })
|
|
|
|
function addEntry() {
|
|
entries.value.push({ subject_type: 'user', subject_id: '', permissions: [] })
|
|
}
|
|
|
|
function removeEntry(idx: number) {
|
|
entries.value.splice(idx, 1)
|
|
}
|
|
|
|
async function save() {
|
|
await setAcl(props.resourceType, props.resourceId, entries.value)
|
|
ElMessage.success('ACL 已保存')
|
|
visible.value = false
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<el-dialog v-model="visible" title="资源授权 (ACL)" width="640px">
|
|
<div v-loading="loading">
|
|
<el-button type="primary" size="small" @click="addEntry">添加授权项</el-button>
|
|
<div v-for="(entry, idx) in entries" :key="idx" class="acl-row">
|
|
<el-select v-model="entry.subject_type" style="width: 140px">
|
|
<el-option label="用户" value="user" />
|
|
<el-option label="项目角色" value="project_role" />
|
|
</el-select>
|
|
<el-input v-model="entry.subject_id" placeholder="subject ID" style="width: 200px" />
|
|
<el-checkbox-group v-model="entry.permissions">
|
|
<el-checkbox v-for="p in ALL_PERMS" :key="p" :value="p">{{ p }}</el-checkbox>
|
|
</el-checkbox-group>
|
|
<el-button link type="danger" @click="removeEntry(idx)">删除</el-button>
|
|
</div>
|
|
<el-empty v-if="entries.length === 0" description="暂无授权" />
|
|
</div>
|
|
<template #footer>
|
|
<el-button @click="visible = false">取消</el-button>
|
|
<el-button type="primary" @click="save">保存</el-button>
|
|
</template>
|
|
</el-dialog>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
.acl-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
margin-top: 12px;
|
|
flex-wrap: wrap;
|
|
}
|
|
</style>
|