WishDetailView.vue 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. <template>
  2. <div class="wish-detail-page">
  3. <van-nav-bar title="愿望详情" left-text="返回" left-arrow @click-left="$router.back()" />
  4. <div v-if="wish" class="wish-detail">
  5. <div class="wish-content-box">
  6. <p class="wish-text">{{ wish.content }}</p>
  7. </div>
  8. <div class="wish-images-box" v-if="wish.images?.length">
  9. <van-image
  10. v-for="(img, i) in wish.images"
  11. :key="i"
  12. :src="img"
  13. width="100%"
  14. fit="contain"
  15. radius="8"
  16. style="margin-bottom: 8px"
  17. />
  18. </div>
  19. <div class="wish-tags-box" v-if="wish.tags?.length">
  20. <van-tag v-for="t in wish.tags" :key="t" plain type="primary" size="medium">
  21. {{ t }}
  22. </van-tag>
  23. </div>
  24. <div class="wish-meta-box">
  25. <div class="meta-item">
  26. <span class="meta-label">许愿树</span>
  27. <span class="meta-value">{{ wish.treeName }}</span>
  28. </div>
  29. <div class="meta-item">
  30. <span class="meta-label">地点</span>
  31. <span class="meta-value">{{ wish.address }}</span>
  32. </div>
  33. <div class="meta-item">
  34. <span class="meta-label">时间</span>
  35. <span class="meta-value">{{ wish.createdAt }}</span>
  36. </div>
  37. <div class="meta-item">
  38. <span class="meta-label">可见性</span>
  39. <span class="meta-value">{{ wish.isPublic ? '公开' : '仅自己可见' }}</span>
  40. </div>
  41. </div>
  42. <div class="wish-actions">
  43. <van-button icon="good-job-o" type="default" round @click="handleLike">
  44. 祝福 {{ wish.likes }}
  45. </van-button>
  46. <van-button
  47. v-if="isOwner"
  48. icon="delete-o"
  49. type="danger"
  50. round
  51. plain
  52. @click="handleDelete"
  53. >
  54. 删除
  55. </van-button>
  56. </div>
  57. </div>
  58. <van-loading v-else class="loading" />
  59. </div>
  60. </template>
  61. <script setup lang="ts">
  62. import { ref, computed, onMounted } from 'vue'
  63. import { useRoute, useRouter } from 'vue-router'
  64. import { showConfirmDialog, showSuccessToast } from 'vant'
  65. import { useUserStore } from '@/stores/user'
  66. import { fetchWishDetail, removeWish, toggleLikeWish } from '@/api/wish'
  67. import type { Wish } from '@/mock/data'
  68. const route = useRoute()
  69. const router = useRouter()
  70. const userStore = useUserStore()
  71. const wish = ref<Wish | null>(null)
  72. const isOwner = computed(() => wish.value?.userId === userStore.phone)
  73. async function handleLike() {
  74. if (!wish.value) return
  75. const likes = await toggleLikeWish(wish.value.id)
  76. wish.value.likes = likes
  77. showSuccessToast('已送上祝福 ❤')
  78. }
  79. async function handleDelete() {
  80. if (!wish.value) return
  81. await showConfirmDialog({ title: '确定删除这个愿望吗?', message: '删除后不可恢复' })
  82. await removeWish(wish.value.id, userStore.phone)
  83. showSuccessToast('愿望已删除')
  84. router.replace('/my-wishes')
  85. }
  86. onMounted(async () => {
  87. const id = Number(route.params.id)
  88. wish.value = await fetchWishDetail(id)
  89. })
  90. </script>
  91. <style scoped>
  92. .wish-detail-page {
  93. min-height: 100vh;
  94. background: #f7f8fa;
  95. }
  96. .wish-detail {
  97. padding: 12px;
  98. }
  99. .wish-content-box {
  100. background: #fff;
  101. border-radius: 12px;
  102. padding: 20px;
  103. margin-bottom: 12px;
  104. }
  105. .wish-text {
  106. font-size: 17px;
  107. line-height: 1.8;
  108. white-space: pre-wrap;
  109. }
  110. .wish-images-box {
  111. margin-bottom: 12px;
  112. }
  113. .wish-tags-box {
  114. display: flex;
  115. flex-wrap: wrap;
  116. gap: 6px 4px;
  117. margin-bottom: 12px;
  118. }
  119. .wish-meta-box {
  120. background: #fff;
  121. border-radius: 12px;
  122. padding: 16px;
  123. margin-bottom: 12px;
  124. }
  125. .meta-item {
  126. display: flex;
  127. justify-content: space-between;
  128. padding: 6px 0;
  129. font-size: 14px;
  130. }
  131. .meta-label {
  132. color: #999;
  133. }
  134. .meta-value {
  135. color: #333;
  136. }
  137. .wish-actions {
  138. display: flex;
  139. gap: 12px;
  140. justify-content: center;
  141. padding: 20px 0;
  142. }
  143. .loading {
  144. margin: 100px auto;
  145. }
  146. </style>