feat: Phase 1-3 全部完成 — 沙盒增强、学情分析、学习路径
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<view class="post-detail">
|
||||
<view class="post" v-if="post.id">
|
||||
<text class="title">{{ post.title }}</text>
|
||||
<view class="meta">
|
||||
<text class="author">{{ post.user?.nickname || '匿名' }}</text>
|
||||
<text class="time">{{ post.createdAt?.slice(0, 10) }}</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<text>{{ post.content }}</text>
|
||||
</view>
|
||||
<view class="actions">
|
||||
<text class="action" @tap="toggleLike">{{ liked ? '❤️' : '🤍' }} {{ post.likeCount }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="comments-section">
|
||||
<text class="section-title">评论 ({{ post.comments?.length || 0 }})</text>
|
||||
<view class="comment-list">
|
||||
<view class="comment" v-for="c in post.comments" :key="c.id">
|
||||
<text class="comment-author">{{ c.user?.nickname || '匿名' }}</text>
|
||||
<text class="comment-content">{{ c.content }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="comment-input-area">
|
||||
<input class="comment-input" v-model="commentText" placeholder="写评论..." />
|
||||
<button class="btn-submit" @tap="submitComment">发送</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { api } from '../../api/index'
|
||||
import { useUserStore } from '../../store/user'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const post = ref<any>({})
|
||||
const liked = ref(false)
|
||||
const commentText = ref('')
|
||||
|
||||
onMounted(async () => {
|
||||
const id = Number((uni as any).getCurrentInstance()?.router?.params?.id || '')
|
||||
try {
|
||||
const [detail, likeStatus] = await Promise.all([
|
||||
api.community.postDetail(id),
|
||||
userStore.isLoggedIn ? api.community.checkLike(id) : Promise.resolve({ liked: false }),
|
||||
])
|
||||
post.value = detail
|
||||
liked.value = (likeStatus as any)?.liked || false
|
||||
} catch (e) {
|
||||
uni.showToast({ title: '加载失败', icon: 'none' })
|
||||
}
|
||||
})
|
||||
|
||||
async function toggleLike() {
|
||||
if (!userStore.isLoggedIn) { uni.navigateTo({ url: '/pages/login/index' }); return }
|
||||
try {
|
||||
await api.community.toggleLike(post.value.id)
|
||||
liked.value = !liked.value
|
||||
post.value.likeCount += liked.value ? 1 : -1
|
||||
} catch (e) { /* ignore */ }
|
||||
}
|
||||
|
||||
async function submitComment() {
|
||||
if (!userStore.isLoggedIn) { uni.navigateTo({ url: '/pages/login/index' }); return }
|
||||
if (!commentText.value) { uni.showToast({ title: '请输入评论内容', icon: 'none' }); return }
|
||||
try {
|
||||
await api.community.addComment(post.value.id, commentText.value)
|
||||
commentText.value = ''
|
||||
uni.showToast({ title: '评论成功', icon: 'success' })
|
||||
const detail: any = await api.community.postDetail(post.value.id)
|
||||
post.value = detail
|
||||
} catch (e: any) {
|
||||
uni.showToast({ title: e.message || '评论失败', icon: 'none' })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.post-detail { padding: 30rpx; }
|
||||
.post { background: #fff; border-radius: 16rpx; padding: 30rpx; }
|
||||
.title { font-size: 36rpx; font-weight: bold; display: block; margin-bottom: 16rpx; }
|
||||
.meta { display: flex; justify-content: space-between; margin-bottom: 24rpx; }
|
||||
.author { font-size: 24rpx; color: #4f8cff; }
|
||||
.time { font-size: 22rpx; color: #ccc; }
|
||||
.content { font-size: 28rpx; color: #333; line-height: 1.8; margin-bottom: 24rpx; }
|
||||
.actions { }
|
||||
.action { font-size: 26rpx; color: #666; }
|
||||
.comments-section { margin-top: 30rpx; }
|
||||
.section-title { font-size: 30rpx; font-weight: bold; display: block; margin-bottom: 20rpx; }
|
||||
.comment-list { background: #fff; border-radius: 16rpx; padding: 20rpx; }
|
||||
.comment { padding: 16rpx 0; border-bottom: 1rpx solid #f5f5f5; }
|
||||
.comment:last-child { border-bottom: none; }
|
||||
.comment-author { font-size: 24rpx; color: #4f8cff; display: block; margin-bottom: 8rpx; }
|
||||
.comment-content { font-size: 26rpx; color: #333; }
|
||||
.comment-input-area { display: flex; align-items: center; gap: 16rpx; margin-top: 24rpx; }
|
||||
.comment-input { flex: 1; background: #fff; border-radius: 12rpx; padding: 20rpx 24rpx; font-size: 26rpx; border: 1rpx solid #e8e8e8; }
|
||||
.btn-submit { background: #4f8cff; color: #fff; border-radius: 10rpx; padding: 16rpx 32rpx; font-size: 26rpx; border: none; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user