- Login page: toggle between admin/sub-account login - Auth store: isAdmin/isIamUser computed properties - MainLayout: role-based sidebar (admin sees all, sub-account sees only my keys) - HomeRedirect: auto-redirect based on role - MyKeysView: sub-account can view/reveal their own API Keys - Portal is completely isolated from admin functions Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
78 lines
2.5 KiB
Vue
78 lines
2.5 KiB
Vue
<template>
|
||
<div style="max-width: 1000px; margin: 0 auto;">
|
||
<h2 style="margin-bottom: 16px;">我的 API Key</h2>
|
||
|
||
<el-table :data="keys" stripe v-loading="loading" style="width: 100%;"
|
||
empty-text="暂无 API Key,请联系管理员分配">
|
||
<el-table-column prop="project_name" label="所属项目" min-width="150" />
|
||
<el-table-column prop="key_name" label="名称/用途" min-width="180" />
|
||
<el-table-column label="API Key" min-width="260">
|
||
<template #default="{ row }">
|
||
<template v-if="revealedKeys[row.id]">
|
||
<code style="font-size: 13px; color: #409eff; word-break: break-all;">
|
||
{{ revealedKeys[row.id] }}
|
||
</code>
|
||
<el-button size="small" text @click="copyKey(revealedKeys[row.id])"
|
||
style="margin-left: 4px;">复制</el-button>
|
||
</template>
|
||
<template v-else>
|
||
<code style="color: #999;">{{ row.api_key_hint }}</code>
|
||
<el-button size="small" text type="primary" @click="handleReveal(row)"
|
||
style="margin-left: 4px;">查看</el-button>
|
||
</template>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="状态" width="90">
|
||
<template #default="{ row }">
|
||
<el-tag :type="row.status === 'active' ? 'success' : 'danger'" size="small">
|
||
{{ row.status === 'active' ? '启用' : '停用' }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="remark" label="备注" min-width="120" show-overflow-tooltip />
|
||
</el-table>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, reactive, onMounted } from 'vue'
|
||
import { ElMessage } from 'element-plus'
|
||
import api from '../../api'
|
||
|
||
const keys = ref([])
|
||
const loading = ref(false)
|
||
const revealedKeys = reactive({})
|
||
|
||
async function loadKeys() {
|
||
loading.value = true
|
||
try {
|
||
const { data } = await api.get('/api/v1/auth/iam/my-keys/')
|
||
keys.value = data
|
||
} catch (e) {
|
||
keys.value = []
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
async function handleReveal(row) {
|
||
try {
|
||
const { data } = await api.get(`/api/v1/auth/iam/my-keys/${row.id}/reveal/`)
|
||
revealedKeys[row.id] = data.api_key
|
||
} catch (e) {
|
||
ElMessage.error('获取 Key 失败')
|
||
}
|
||
}
|
||
|
||
async function copyKey(key) {
|
||
try {
|
||
await navigator.clipboard.writeText(key)
|
||
ElMessage.success('已复制')
|
||
} catch {
|
||
ElMessage.error('复制失败')
|
||
}
|
||
}
|
||
|
||
onMounted(loadKeys)
|
||
</script>
|