You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

147 lines
3.7 KiB

<script setup lang="ts">
import { request, unwrapApiBody, type ApiResponse } from '../../../../utils/http/factory'
import { useAuthSession } from '../../../../composables/useAuthSession'
definePageMeta({ title: '用户管理' })
const { user, refresh } = useAuthSession()
const rows = ref<
{ id: number; username: string; role: string; status: string; publicSlug: string | null }[]
>([])
const loading = ref(true)
const form = reactive({ username: '', password: '', email: '' })
const creating = ref(false)
async function ensureAdmin() {
await refresh(true)
if (user.value?.role !== 'admin') {
await navigateTo('/me')
}
}
async function load() {
loading.value = true
try {
const res = await request<ApiResponse<{ users: typeof rows.value }>>('/api/admin/users')
rows.value = unwrapApiBody(res).users
} finally {
loading.value = false
}
}
onMounted(async () => {
await ensureAdmin()
await load()
})
async function createUser() {
creating.value = true
try {
await request('/api/admin/users', {
method: 'POST',
body: {
username: form.username,
password: form.password,
email: form.email || null,
},
})
form.username = ''
form.password = ''
form.email = ''
await load()
} finally {
creating.value = false
}
}
async function setStatus(id: number, status: 'active' | 'disabled') {
await request(`/api/admin/users/${id}`, { method: 'PATCH', body: { status } })
await load()
}
</script>
<template>
<UContainer class="py-8 space-y-8 max-w-4xl">
<h1 class="text-2xl font-semibold">
用户管理
</h1>
<UCard>
<template #header>
新建用户
</template>
<div class="grid sm:grid-cols-3 gap-2">
<UInput v-model="form.username" placeholder="用户名" />
<UInput v-model="form.password" type="password" placeholder="初始密码" />
<UInput v-model="form.email" placeholder="邮箱(可选)" />
</div>
<UButton class="mt-3" :loading="creating" @click="createUser">
创建
</UButton>
</UCard>
<UCard>
<template #header>
用户列表
</template>
<div v-if="loading" class="text-muted">
加载中…
</div>
<table v-else class="w-full text-sm">
<thead>
<tr class="text-left text-muted border-b border-default">
<th class="pb-2">
id
</th>
<th class="pb-2">
用户名
</th>
<th class="pb-2">
角色
</th>
<th class="pb-2">
状态
</th>
<th class="pb-2" />
</tr>
</thead>
<tbody>
<tr v-for="u in rows" :key="u.id" class="border-b border-default/60">
<td class="py-2">
{{ u.id }}
</td>
<td class="py-2">
{{ u.username }}
</td>
<td class="py-2">
{{ u.role }}
</td>
<td class="py-2">
{{ u.status }}
</td>
<td class="py-2 text-right">
<UButton
v-if="u.status === 'active'"
size="xs"
color="error"
variant="soft"
@click="setStatus(u.id, 'disabled')"
>
禁用
</UButton>
<UButton
v-else
size="xs"
variant="soft"
@click="setStatus(u.id, 'active')"
>
启用
</UButton>
</td>
</tr>
</tbody>
</table>
</UCard>
</UContainer>
</template>