feat(members): split username/display_name, sync updates to authentik, add password reset API and refresh docs

This commit is contained in:
Chris
2026-03-30 22:15:41 +08:00
parent 29e9d9fa28
commit 2fd202250d
2 changed files with 30 additions and 1 deletions

View File

@@ -3,6 +3,7 @@ import { adminHttp } from './http'
export const getMembers = () => adminHttp.get('/admin/members')
export const upsertMember = (data) => adminHttp.post('/admin/members/upsert', data)
export const updateMember = (authentikSub, data) => adminHttp.patch(`/admin/members/${authentikSub}`, data)
export const resetMemberPassword = (authentikSub) => adminHttp.post(`/admin/members/${authentikSub}/password/reset`)
export const getMemberPermissionGroups = (authentikSub) => adminHttp.get(`/admin/members/${authentikSub}/permission-groups`)
export const setMemberPermissionGroups = (authentikSub, groupKeys) =>
adminHttp.put(`/admin/members/${authentikSub}/permission-groups`, { group_keys: groupKeys })

View File

@@ -14,20 +14,23 @@
<el-table v-else :data="members" stripe border class="w-full shadow-sm">
<template #empty><el-empty description="目前無會員" /></template>
<el-table-column prop="authentik_sub" label="Authentik Sub" min-width="260" />
<el-table-column prop="username" label="Username" min-width="160" />
<el-table-column prop="email" label="Email" min-width="220" />
<el-table-column prop="display_name" label="顯示名稱" min-width="180" />
<el-table-column prop="is_active" label="啟用" width="100">
<template #default="{ row }">{{ row.is_active ? '是' : '否' }}</template>
</el-table-column>
<el-table-column label="操作" width="120">
<el-table-column label="操作" width="220">
<template #default="{ row }">
<el-button size="small" @click="openEdit(row)">編輯</el-button>
<el-button size="small" type="warning" @click="handleResetPassword(row)">重設密碼</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog v-model="showCreateDialog" title="新增會員" @close="resetCreateForm">
<el-form ref="createFormRef" :model="createForm" :rules="createRules" label-width="120px">
<el-form-item label="Username" prop="username"><el-input v-model="createForm.username" /></el-form-item>
<el-form-item label="Email" prop="email"><el-input v-model="createForm.email" /></el-form-item>
<el-form-item label="顯示名稱" prop="display_name"><el-input v-model="createForm.display_name" /></el-form-item>
<el-form-item label="權限群組">
@@ -47,6 +50,7 @@
<el-dialog v-model="showEditDialog" title="編輯會員" @close="resetEditForm">
<el-form :model="editForm" label-width="120px">
<el-form-item label="Authentik Sub"><el-input :model-value="editForm.authentik_sub" disabled /></el-form-item>
<el-form-item label="Username"><el-input v-model="editForm.username" /></el-form-item>
<el-form-item label="Email"><el-input v-model="editForm.email" /></el-form-item>
<el-form-item label="顯示名稱"><el-input v-model="editForm.display_name" /></el-form-item>
<el-form-item label="權限群組">
@@ -73,6 +77,7 @@ import {
getMembers,
upsertMember,
updateMember,
resetMemberPassword,
getMemberPermissionGroups,
setMemberPermissionGroups
} from '@/api/members'
@@ -88,6 +93,7 @@ const showCreateDialog = ref(false)
const createFormRef = ref()
const creating = ref(false)
const createForm = ref({
username: '',
email: '',
display_name: '',
group_keys: [],
@@ -95,6 +101,7 @@ const createForm = ref({
sync_to_authentik: true
})
const createRules = {
username: [{ required: true, message: '請輸入 Username', trigger: 'blur' }],
email: [{ required: true, message: '請輸入 Email', trigger: 'blur' }]
}
@@ -102,6 +109,7 @@ const showEditDialog = ref(false)
const saving = ref(false)
const editForm = ref({
authentik_sub: '',
username: '',
email: '',
display_name: '',
group_keys: [],
@@ -126,6 +134,7 @@ async function load() {
function resetCreateForm() {
createForm.value = {
username: '',
email: '',
display_name: '',
group_keys: [],
@@ -137,6 +146,7 @@ function resetCreateForm() {
async function openEdit(row) {
editForm.value = {
authentik_sub: row.authentik_sub,
username: row.username || '',
email: row.email || '',
display_name: row.display_name || '',
group_keys: [],
@@ -155,6 +165,7 @@ async function openEdit(row) {
function resetEditForm() {
editForm.value = {
authentik_sub: '',
username: '',
email: '',
display_name: '',
group_keys: [],
@@ -189,6 +200,7 @@ async function handleEdit() {
saving.value = true
try {
await updateMember(editForm.value.authentik_sub, {
username: editForm.value.username || null,
email: editForm.value.email || null,
display_name: editForm.value.display_name || null,
is_active: editForm.value.is_active,
@@ -206,5 +218,21 @@ async function handleEdit() {
}
}
async function handleResetPassword(row) {
try {
const res = await resetMemberPassword(row.authentik_sub)
const pwd = res.data?.temporary_password || ''
if (!pwd) {
ElMessage.success('密碼已重設')
return
}
await navigator.clipboard.writeText(pwd)
ElMessage.success(`已重設密碼,臨時密碼已複製:${pwd}`)
} catch (err) {
const detail = err.response?.data?.detail
ElMessage.error(detail || '重設密碼失敗')
}
}
onMounted(load)
</script>