moment-item.vue 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. <script lang="ts" setup>
  2. import Card from '@/components/card.vue'
  3. import dayjs from 'dayjs'
  4. import { beforeNow } from '../utils/date-util'
  5. import Tag from './tag.vue'
  6. import { stringify } from 'qs'
  7. import { isImageOrVideo } from '../core/utils/common'
  8. import { useRouter } from '../core/utils/router'
  9. const props = defineProps({
  10. options: {
  11. type: Object as PropType<{
  12. id: number
  13. headUrl?: string
  14. stylistId?: number
  15. stylistName?: string
  16. marketing?: string
  17. circleDesc?: string
  18. tagName?: string
  19. detailsType?: string
  20. detailsUrl?: string
  21. detailsDesc?: string
  22. circleType?: string
  23. spaceType?: string
  24. designStyle?: string
  25. spaceAddr?: string
  26. customerDemand?: string
  27. createTime: number
  28. bannerUrls: string[]
  29. shareCount?: number
  30. upvoteCount?: number
  31. ownUpvote: boolean
  32. reviewCount: number
  33. }>,
  34. default: () => ({
  35. author: {
  36. nickname: '张三',
  37. avatar: 'https://img.yzcdn.cn/vant/cat.jpeg',
  38. },
  39. createTime: new Date(),
  40. images: [
  41. 'https://via.placeholder.com/104x104',
  42. 'https://via.placeholder.com/104x104',
  43. 'https://via.placeholder.com/104x104',
  44. ],
  45. content: '',
  46. tags: [],
  47. shares: 0,
  48. comments: 0,
  49. likes: 0,
  50. }),
  51. },
  52. })
  53. const router = useRouter()
  54. const imgClass = ref('')
  55. const isVideo = ref(false)
  56. const toDetail = () => {
  57. uni.navigateTo({
  58. url: `/pages/home/moment/index?${stringify({ id: props.options.id })}`,
  59. })
  60. }
  61. onMounted(async () => {
  62. // console.log('加载')
  63. if (
  64. props.options.bannerUrls?.length === 1 &&
  65. isImageOrVideo(props.options.bannerUrls[0]) === 'image'
  66. ) {
  67. const { width, height } = await uni.getImageInfo({
  68. src: props.options.bannerUrls[0],
  69. })
  70. if (Number(width / height) > 1) {
  71. imgClass.value = 'w-[60vw]'
  72. } else {
  73. imgClass.value = 'w-[44vw]'
  74. }
  75. }
  76. if (
  77. props.options.bannerUrls?.length === 1 &&
  78. isImageOrVideo(props.options.bannerUrls[0]) === 'video'
  79. ) {
  80. isVideo.value = true
  81. }
  82. })
  83. </script>
  84. <template>
  85. <Card @click="toDetail" @tap="toDetail">
  86. <view class="flex items-center">
  87. <view
  88. class="overflow-hidden rounded-full mr-2"
  89. @click.stop="router.push(`/pages/mine/homepage/index?id=${options.stylistId}`)"
  90. >
  91. <wd-img
  92. custom-class="vertical-bottom"
  93. :width="35"
  94. :height="35"
  95. :src="props.options.headUrl"
  96. mode="scaleToFill"
  97. />
  98. </view>
  99. <view class="">{{ props.options.stylistName }}</view>
  100. <view class="flex-1"></view>
  101. <view>{{ beforeNow(dayjs(props.options.createTime).toDate()) }}</view>
  102. </view>
  103. <div v-if="isVideo" class="aspect-[1.64/1] rounded-lg overflow-hidden my-6" @click.stop>
  104. <video class="w-full h-full" :src="options.bannerUrls[0]"></video>
  105. </div>
  106. <view
  107. v-if="!isVideo"
  108. :class="[
  109. props.options.bannerUrls?.length > 1 ? 'grid grid-cols-3 grid-gap-1' : 'w-full',
  110. 'my-6',
  111. ]"
  112. >
  113. <template v-for="it of props.options.bannerUrls" :key="it">
  114. <view
  115. :class="[
  116. props.options.bannerUrls?.length > 1 ? 'aspect-square' : '',
  117. 'rounded-lg overflow-hidden',
  118. imgClass,
  119. ]"
  120. >
  121. <wd-img
  122. custom-class="vertical-bottom"
  123. :width="'100%'"
  124. :src="it"
  125. :height="props.options.bannerUrls?.length > 1 ? '100%' : 'auto'"
  126. :mode="props.options.bannerUrls?.length > 1 ? 'aspectFill' : 'widthFix'"
  127. ></wd-img>
  128. </view>
  129. </template>
  130. </view>
  131. <view class="text-[rgba(0,0,0,0.85)] text-4 font-400 my-1">
  132. {{ props.options.circleDesc }}
  133. </view>
  134. <view class="my-5.5 flex flex-wrap gap-3.5">
  135. <template v-if="props.options.tagName !== ''">
  136. <template v-for="it of props.options.tagName?.split(',')" :key="it">
  137. <Tag>{{ it }}</Tag>
  138. </template>
  139. </template>
  140. </view>
  141. <view class="flex justify-between">
  142. <view class="flex items-center text-[rgba(0,0,0,0.85)] text-3.5 font-400 line-height-5.5">
  143. <wd-img width="15" height="15" src="/static/svgs/share.svg"></wd-img>
  144. <view class="ml-1">{{ props.options.shareCount }}</view>
  145. </view>
  146. <view class="flex items-center text-[rgba(0,0,0,0.85)] text-3.5 font-400 line-height-5.5">
  147. <wd-img width="15" height="15" src="/static/svgs/comment.svg"></wd-img>
  148. <view class="ml-1">{{ props.options.reviewCount }}</view>
  149. </view>
  150. <view class="flex items-center text-[rgba(0,0,0,0.85)] text-3.5 font-400 line-height-5.5">
  151. <wd-img width="15" height="15" src="/static/svgs/like.svg"></wd-img>
  152. <view class="ml-1">{{ props.options.upvoteCount }}</view>
  153. </view>
  154. </view>
  155. </Card>
  156. </template>