Files
ai-learning-platform/mobile/src/pages/post-detail/index.vue
T
yuzhiran-dev 21078ae287 feat: Mobile 全站 CSS 变量对齐
- 批量替换 18 个页面硬编码颜色 → CSS 变量
- sandbox page 完整迁移(参考页)
- App.vue + variables.css 统一 Token 定义
- 剩余仅保留语义色(红色价格、绿色完成、阴影、渐变)
- 剩余 16 页按相同模式可逐步迁移
2026-05-18 11:52:57 +08:00

101 lines
4.2 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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: var(--card); 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: var(--brand); }
.time { font-size: 22rpx; color: var(--muted-foreground); }
.content { font-size: 28rpx; color: var(--foreground); line-height: 1.8; margin-bottom: 24rpx; }
.actions { }
.action { font-size: 26rpx; color: var(--muted-foreground); }
.comments-section { margin-top: 30rpx; }
.section-title { font-size: 30rpx; font-weight: bold; display: block; margin-bottom: 20rpx; }
.comment-list { background: var(--card); border-radius: 16rpx; padding: 20rpx; }
.comment { padding: 16rpx 0; border-bottom: 1rpx solid var(--muted); }
.comment:last-child { border-bottom: none; }
.comment-author { font-size: 24rpx; color: var(--brand); display: block; margin-bottom: 8rpx; }
.comment-content { font-size: 26rpx; color: var(--foreground); }
.comment-input-area { display: flex; align-items: center; gap: 16rpx; margin-top: 24rpx; }
.comment-input { flex: 1; background: var(--card); border-radius: 12rpx; padding: 20rpx 24rpx; font-size: 26rpx; border: 1rpx solid var(--border); }
.btn-submit { background: var(--brand); color: var(--card); border-radius: 10rpx; padding: 16rpx 32rpx; font-size: 26rpx; border: none; }
</style>