1.5
This commit is contained in:
@@ -2,11 +2,12 @@
|
||||
<div class="moment-card">
|
||||
<!-- 头部:头像 + 用户名 + 时间 + 删除 -->
|
||||
<div class="moment-header">
|
||||
<n-avatar :size="40" round :style="{ background: 'var(--color-primary)' }">
|
||||
<n-avatar :size="40" round :style="{ background: 'var(--color-primary)', cursor: isMine ? 'default' : 'pointer' }"
|
||||
@click="goToUserMoments">
|
||||
{{ (moment.nickname || moment.username || '?')[0] }}
|
||||
</n-avatar>
|
||||
<div class="header-info">
|
||||
<span class="author-name">{{ moment.nickname || moment.username }}</span>
|
||||
<span class="author-name" :style="{ cursor: isMine ? 'default' : 'pointer' }" @click="goToUserMoments">{{ moment.nickname || moment.username }}</span>
|
||||
<span class="post-time">{{ formatTime(moment.created_at) }}</span>
|
||||
</div>
|
||||
<span v-if="isMine" class="delete-btn" title="删除" @click="handleDelete">🗑️</span>
|
||||
@@ -66,6 +67,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { momentsApi } from '@/api/moments'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import dayjs from 'dayjs'
|
||||
@@ -83,6 +85,7 @@ const emit = defineEmits<{
|
||||
}>()
|
||||
|
||||
const auth = useAuthStore()
|
||||
const router = useRouter()
|
||||
const showComments = ref(false)
|
||||
const comments = ref<any[]>([])
|
||||
const commentText = ref('')
|
||||
@@ -90,6 +93,12 @@ const replyTarget = ref<any>(null)
|
||||
|
||||
const isMine = computed(() => props.moment.user_id === auth.user?.id)
|
||||
|
||||
function goToUserMoments() {
|
||||
if (props.moment.user_id && !isMine.value) {
|
||||
router.push(`/moments/user/${props.moment.user_id}`)
|
||||
}
|
||||
}
|
||||
|
||||
watch(showComments, async (val) => {
|
||||
if (val && comments.value.length === 0) {
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
<template>
|
||||
<div class="user-moments">
|
||||
<div class="panel-header">
|
||||
<n-button quaternary circle size="small" @click="$router.push('/moments')">←</n-button>
|
||||
<h3 class="panel-title">{{ userName }} 的朋友圈</h3>
|
||||
</div>
|
||||
<div class="moments-content">
|
||||
<div v-if="isLoading" class="loading">加载中...</div>
|
||||
<div v-else-if="moments.length === 0" class="empty">
|
||||
<div style="font-size: 48px">🌿</div>
|
||||
<p style="color: var(--color-text-secondary)">还没有动态</p>
|
||||
</div>
|
||||
<div v-else class="moment-list">
|
||||
<MomentCard
|
||||
v-for="moment in moments"
|
||||
:key="moment.id"
|
||||
:moment="moment"
|
||||
@toggle-like="handleToggleLike"
|
||||
@comment="handleComment"
|
||||
@delete="handleDelete"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="hasMore && moments.length > 0" class="load-more">
|
||||
<n-button text size="small" @click="loadMore">加载更多</n-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useMessage } from 'naive-ui'
|
||||
import { momentsApi } from '@/api/moments'
|
||||
import MomentCard from './MomentCard.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const message = useMessage()
|
||||
|
||||
const moments = ref<any[]>([])
|
||||
const isLoading = ref(false)
|
||||
const hasMore = ref(true)
|
||||
const cursor = ref<string | null>(null)
|
||||
const userName = ref('用户')
|
||||
|
||||
onMounted(() => {
|
||||
const userId = route.params.userId as string
|
||||
if (userId) fetchUserMoments(userId, true)
|
||||
})
|
||||
|
||||
async function fetchUserMoments(userId: string, refresh = false) {
|
||||
if (isLoading.value) return
|
||||
isLoading.value = true
|
||||
try {
|
||||
const cur = refresh ? undefined : cursor.value || undefined
|
||||
const { data } = await momentsApi.getUserMoments(userId, cur)
|
||||
if (refresh) {
|
||||
moments.value = data
|
||||
} else {
|
||||
moments.value = [...moments.value, ...data]
|
||||
}
|
||||
if (data.length > 0) {
|
||||
cursor.value = data[data.length - 1].id
|
||||
if (!userName.value || userName.value === '用户') {
|
||||
userName.value = data[0].nickname || data[0].username || '用户'
|
||||
}
|
||||
}
|
||||
if (data.length < 20) hasMore.value = false
|
||||
} catch {
|
||||
message.error('加载失败')
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function loadMore() {
|
||||
const userId = route.params.userId as string
|
||||
fetchUserMoments(userId)
|
||||
}
|
||||
|
||||
async function handleToggleLike(momentId: string) {
|
||||
try {
|
||||
const { data } = await momentsApi.toggleLike(momentId)
|
||||
const m = moments.value.find((m) => m.id === momentId)
|
||||
if (m) {
|
||||
m.is_liked = data.is_liked
|
||||
m.like_count = data.is_liked ? m.like_count + 1 : Math.max(0, m.like_count - 1)
|
||||
}
|
||||
} catch { message.error('操作失败') }
|
||||
}
|
||||
|
||||
async function handleComment(momentId: string, content: string) {
|
||||
message.success('评论成功')
|
||||
}
|
||||
|
||||
async function handleDelete(momentId: string) {
|
||||
try {
|
||||
await momentsApi.deleteMoment(momentId)
|
||||
moments.value = moments.value.filter((m) => m.id !== momentId)
|
||||
message.success('已删除')
|
||||
} catch { message.error('删除失败') }
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.user-moments { display: flex; flex-direction: column; height: 100%; }
|
||||
.panel-header {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
padding: 16px; border-bottom: 1px solid var(--color-border);
|
||||
}
|
||||
.panel-title { margin: 0; font-size: 16px; font-weight: 600; }
|
||||
.moments-content { flex: 1; overflow-y: auto; padding: 12px; }
|
||||
.loading { text-align: center; padding: 40px; color: var(--color-text-hint); }
|
||||
.empty { text-align: center; padding: 60px 20px; }
|
||||
.moment-list { display: flex; flex-direction: column; gap: 12px; }
|
||||
.load-more { text-align: center; padding: 12px; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user