Files
MincedPad/frontend/src/components/WallList.vue
T
2026-07-14 13:01:44 +08:00

139 lines
2.7 KiB
Vue

<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { fetchWall, type Item } from '../api/client'
const router = useRouter()
const items = ref<Item[]>([])
const loading = ref(false)
let timer: number | undefined
async function loadWall(silent = false) {
if (!silent) loading.value = true
try {
const data = await fetchWall(1, 30)
items.value = data.items
} catch (err) {
if (!silent) {
ElMessage.error(err instanceof Error ? err.message : '加载公共墙失败')
}
} finally {
loading.value = false
}
}
function openItem(item: Item) {
router.push(`/p/${item.slug}`)
}
function formatTime(value: string): string {
try {
return new Date(value).toLocaleString('zh-CN', { hour12: false })
} catch {
return value
}
}
function refresh() {
void loadWall(true)
}
defineExpose({ refresh })
onMounted(() => {
void loadWall()
timer = window.setInterval(() => {
void loadWall(true)
}, 15_000)
})
onUnmounted(() => {
if (timer !== undefined) {
window.clearInterval(timer)
}
})
</script>
<template>
<section class="wall">
<div class="wall-head">
<h2>公共墙</h2>
<el-button text type="primary" :loading="loading" @click="loadWall()">刷新</el-button>
</div>
<el-empty v-if="!loading && items.length === 0" description="暂无公开内容" />
<div v-else class="wall-list">
<button
v-for="item in items"
:key="item.slug"
type="button"
class="wall-item"
@click="openItem(item)"
>
<div class="title">{{ item.title || item.file_name || item.slug }}</div>
<div class="meta">
<span>{{ item.kind === 'file' ? '文件' : '文本' }}</span>
<span>{{ formatTime(item.created_at) }}</span>
<span v-if="item.burn_after_read">阅后即焚</span>
</div>
</button>
</div>
</section>
</template>
<style scoped>
.wall-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
margin-bottom: 12px;
}
.wall-head h2 {
margin: 0;
font-size: 1.15rem;
}
.wall-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.wall-item {
display: block;
width: 100%;
text-align: left;
border: 1px solid #e4e7ed;
background: #fff;
border-radius: 8px;
padding: 14px 12px;
min-height: 56px;
cursor: pointer;
font: inherit;
color: inherit;
}
.wall-item:active {
background: #f0f2f5;
}
.title {
font-weight: 600;
margin-bottom: 6px;
word-break: break-word;
}
.meta {
display: flex;
flex-wrap: wrap;
gap: 8px 12px;
font-size: 0.85rem;
color: #909399;
}
</style>