21078ae287
- 批量替换 18 个页面硬编码颜色 → CSS 变量 - sandbox page 完整迁移(参考页) - App.vue + variables.css 统一 Token 定义 - 剩余仅保留语义色(红色价格、绿色完成、阴影、渐变) - 剩余 16 页按相同模式可逐步迁移
101 lines
4.2 KiB
Vue
101 lines
4.2 KiB
Vue
<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>
|