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.
113 lines
3.1 KiB
113 lines
3.1 KiB
<script setup lang="ts">
|
|
import { request, unwrapApiBody, type ApiResponse } from '../../../utils/http/factory'
|
|
import { useAuthSession } from '../../../composables/useAuthSession'
|
|
|
|
definePageMeta({ title: '文章' })
|
|
|
|
type Row = { id: number; title: string; slug: string; visibility: string }
|
|
|
|
const posts = ref<Row[]>([])
|
|
const loading = ref(true)
|
|
const jumpIdRaw = ref('')
|
|
const toast = useToast()
|
|
const { user, refresh: refreshAuth } = useAuthSession()
|
|
|
|
async function load() {
|
|
loading.value = true
|
|
try {
|
|
const res = await request<ApiResponse<{ posts: Row[] }>>('/api/me/posts')
|
|
posts.value = unwrapApiBody(res).posts
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
onMounted(() => {
|
|
void refreshAuth(true)
|
|
void load()
|
|
})
|
|
|
|
function publicPostHref(slug: string) {
|
|
const ps = user.value?.publicSlug
|
|
if (!ps) {
|
|
return ''
|
|
}
|
|
return `/@${ps}/posts/${encodeURIComponent(slug)}`
|
|
}
|
|
|
|
function goEditById() {
|
|
const n = Number.parseInt(jumpIdRaw.value.trim(), 10)
|
|
if (!Number.isFinite(n) || n < 1) {
|
|
toast.add({ title: '请输入有效的文章 ID(正整数)', color: 'error' })
|
|
return
|
|
}
|
|
void navigateTo(`/me/posts/${n}`)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<UContainer class="py-8 space-y-4 max-w-3xl">
|
|
<div class="flex flex-wrap justify-between items-center gap-3">
|
|
<h1 class="text-2xl font-semibold">
|
|
文章
|
|
</h1>
|
|
<UButton to="/me/posts/new">
|
|
新建
|
|
</UButton>
|
|
</div>
|
|
|
|
<UCard :ui="{ body: 'p-4 sm:p-5' }">
|
|
<div class="flex flex-wrap items-end gap-3">
|
|
<UFormField label="按 ID 打开编辑" class="min-w-[200px] flex-1">
|
|
<UInput
|
|
v-model="jumpIdRaw"
|
|
placeholder="例如 1"
|
|
type="text"
|
|
autocomplete="off"
|
|
@keydown.enter.prevent="goEditById"
|
|
/>
|
|
</UFormField>
|
|
<UButton color="neutral" @click="goEditById">
|
|
跳转
|
|
</UButton>
|
|
</div>
|
|
</UCard>
|
|
|
|
<div v-if="loading" class="text-muted">
|
|
加载中…
|
|
</div>
|
|
<UEmpty v-else-if="!posts.length" title="暂无文章" description="创建第一篇 Markdown 文章" />
|
|
<ul v-else class="space-y-2">
|
|
<li
|
|
v-for="p in posts"
|
|
:key="p.id"
|
|
class="flex flex-wrap justify-between items-center gap-3 border border-default rounded-lg p-3"
|
|
>
|
|
<div class="min-w-0 flex-1">
|
|
<div class="font-medium truncate">
|
|
{{ p.title }}
|
|
</div>
|
|
<div class="text-xs text-muted">
|
|
id {{ p.id }} · /{{ p.slug }} · {{ p.visibility }}
|
|
</div>
|
|
</div>
|
|
<div class="flex flex-wrap gap-1 justify-end">
|
|
<UButton
|
|
v-if="user?.publicSlug && p.visibility === 'public'"
|
|
:to="publicPostHref(p.slug)"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
size="xs"
|
|
variant="soft"
|
|
color="neutral"
|
|
>
|
|
公开页
|
|
</UButton>
|
|
<UButton :to="`/me/posts/${p.id}`" size="xs" variant="ghost">
|
|
编辑
|
|
</UButton>
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
</UContainer>
|
|
</template>
|
|
|