|
|
|
@ -1,18 +1,39 @@ |
|
|
|
<script setup lang="ts"> |
|
|
|
import { request, unwrapApiBody, type ApiResponse } from '../../../../utils/http/factory' |
|
|
|
import { useAuthSession } from '../../../../composables/useAuthSession' |
|
|
|
import { buildPublicProfileAbsoluteUrl } from '../../../../utils/public-profile-url' |
|
|
|
|
|
|
|
definePageMeta({ title: '用户管理' }) |
|
|
|
|
|
|
|
const { user, refresh } = useAuthSession() |
|
|
|
const toast = useToast() |
|
|
|
|
|
|
|
const rows = ref< |
|
|
|
{ id: number; username: string; role: string; status: string; publicSlug: string | null }[] |
|
|
|
{ |
|
|
|
id: number |
|
|
|
username: string |
|
|
|
role: string |
|
|
|
status: string |
|
|
|
publicSlug: string | null |
|
|
|
postCount: number |
|
|
|
timelineEventCount: number |
|
|
|
rssFeedCount: number |
|
|
|
}[] |
|
|
|
>([]) |
|
|
|
const loading = ref(true) |
|
|
|
const form = reactive({ username: '', password: '', email: '' }) |
|
|
|
const creating = ref(false) |
|
|
|
|
|
|
|
async function copyPublicUrl(publicSlug: string) { |
|
|
|
const href = buildPublicProfileAbsoluteUrl(window.location.origin, publicSlug) |
|
|
|
try { |
|
|
|
await navigator.clipboard.writeText(href) |
|
|
|
toast.add({ title: '已复制公开页链接', color: 'success' }) |
|
|
|
} catch { |
|
|
|
toast.add({ title: '复制失败', color: 'error' }) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
async function ensureAdmin() { |
|
|
|
await refresh(true) |
|
|
|
if (user.value?.role !== 'admin') { |
|
|
|
@ -103,6 +124,18 @@ async function setStatus(id: number, status: 'active' | 'disabled') { |
|
|
|
<th class="pb-2"> |
|
|
|
状态 |
|
|
|
</th> |
|
|
|
<th class="pb-2"> |
|
|
|
文章 |
|
|
|
</th> |
|
|
|
<th class="pb-2"> |
|
|
|
时间线 |
|
|
|
</th> |
|
|
|
<th class="pb-2"> |
|
|
|
RSS 源 |
|
|
|
</th> |
|
|
|
<th class="pb-2"> |
|
|
|
公开页 |
|
|
|
</th> |
|
|
|
<th class="pb-2" /> |
|
|
|
</tr> |
|
|
|
</thead> |
|
|
|
@ -120,6 +153,31 @@ async function setStatus(id: number, status: 'active' | 'disabled') { |
|
|
|
<td class="py-2"> |
|
|
|
{{ u.status }} |
|
|
|
</td> |
|
|
|
<td class="py-2 tabular-nums"> |
|
|
|
{{ u.postCount }} |
|
|
|
</td> |
|
|
|
<td class="py-2 tabular-nums"> |
|
|
|
{{ u.timelineEventCount }} |
|
|
|
</td> |
|
|
|
<td class="py-2 tabular-nums"> |
|
|
|
{{ u.rssFeedCount }} |
|
|
|
</td> |
|
|
|
<td class="py-2"> |
|
|
|
<template v-if="u.publicSlug?.trim()"> |
|
|
|
<div class="flex items-center gap-1 flex-wrap"> |
|
|
|
<NuxtLink |
|
|
|
class="text-primary hover:underline" |
|
|
|
:to="`/@${u.publicSlug.trim()}`" |
|
|
|
> |
|
|
|
@{{ u.publicSlug.trim() }} |
|
|
|
</NuxtLink> |
|
|
|
<UButton size="xs" variant="soft" @click="copyPublicUrl(u.publicSlug.trim())"> |
|
|
|
复制链接 |
|
|
|
</UButton> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
<span v-else class="text-muted">—</span> |
|
|
|
</td> |
|
|
|
<td class="py-2 text-right"> |
|
|
|
<UButton |
|
|
|
v-if="u.status === 'active'" |
|
|
|
|