index.vue 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. <route lang="json">
  2. {
  3. "style": {
  4. "navigationBarTitleText": "详情",
  5. "navigationBarBackgroundColor": "#fff",
  6. "navigationStyle": "custom"
  7. }
  8. }
  9. </route>
  10. <script setup lang="ts">
  11. import Tag from '@/components/tag.vue'
  12. import {
  13. createCircleReview,
  14. getCircle,
  15. getCircleReviews,
  16. getCircleUpvotes,
  17. shareCircle,
  18. } from '../../../core/libs/requests'
  19. import { handleUpvoteClick } from '../../../core/libs/actions'
  20. import CommentItem from '../components/comment-item.vue'
  21. import { useUserStore } from '../../../store'
  22. import { storeToRefs } from 'pinia'
  23. import { isImageOrVideo } from '../../../core/utils/common'
  24. import dayjs from 'dayjs'
  25. import SectionHeading from '@/components/section-heading.vue'
  26. import BottomAppBar from '@/components/bottom-app-bar.vue'
  27. import { likeActived, likeBlack } from '@designer-hub/assets/src/icons'
  28. import NavBarEvo from '@/components/navbar-evo.vue'
  29. import { useRouter } from '../../../core/utils/router'
  30. const userStore = useUserStore()
  31. const { userInfo } = storeToRefs(userStore)
  32. const router = useRouter()
  33. const id = ref()
  34. const { data, run } = useRequest(() => getCircle(id.value), { initialData: {} })
  35. const { data: reviews, run: runGetReviews } = useRequest(
  36. () => getCircleReviews({ circleId: id.value }),
  37. {
  38. initialData: {
  39. list: [],
  40. },
  41. },
  42. )
  43. const { data: circleUpvotes, run: setCircleUpvotes } = useRequest(
  44. () => getCircleUpvotes(id.value),
  45. { initialData: { list: [], total: 0 } },
  46. )
  47. const swiperSizes = ref()
  48. const swiperStyle = ref()
  49. const reviewContent = ref('')
  50. const isVideo = ref(false)
  51. const handleChange = ({ detail: { current } }) => {
  52. swiperStyle.value = {
  53. height: swiperSizes.value[current].height + 'px',
  54. }
  55. }
  56. const setSwiperStyle = async () => {
  57. if (!data.value.bannerUrls.length) return
  58. const { screenWidth } = await uni.getSystemInfo()
  59. if (data.value.bannerUrls.length === 1 && isImageOrVideo(data.value.bannerUrls[0]) === 'video') {
  60. isVideo.value = true
  61. return
  62. }
  63. swiperSizes.value = (
  64. await Promise.all(data.value.bannerUrls.map((src) => uni.getImageInfo({ src })))
  65. ).map(({ width, height }) => ({ width: screenWidth, height: height / (width / screenWidth) }))
  66. swiperStyle.value = {
  67. height: swiperSizes.value[0].height + 'px',
  68. }
  69. }
  70. const handleSend = async () => {
  71. const { code, msg } = await createCircleReview({
  72. circleId: id.value,
  73. userId: userInfo.value.userId,
  74. userName: userInfo.value.nickname,
  75. reviewContent: reviewContent.value,
  76. })
  77. if (code !== 0) {
  78. uni.showToast({ title: msg, icon: 'none' })
  79. } else {
  80. reviewContent.value = ''
  81. uni.showToast({ title: '评论成功', icon: 'none' })
  82. await runGetReviews()
  83. }
  84. }
  85. onMounted(async () => {})
  86. onLoad(async (query: { id: string }) => {
  87. id.value = query.id
  88. await run()
  89. await runGetReviews()
  90. await setSwiperStyle()
  91. await setCircleUpvotes()
  92. })
  93. onShareAppMessage(async () => {
  94. await shareCircle(id.value)
  95. return { title: data.value?.circleDesc }
  96. })
  97. </script>
  98. <template>
  99. <view class="bg-white flex-grow">
  100. <NavBarEvo placeholder>
  101. <template #prepend>
  102. <div
  103. class="flex items-center gap-2"
  104. @click="() => router.push(`/pages/mine/homepage/index?id=${data.stylistId}`)"
  105. >
  106. <wd-img width="24" height="24" round :src="data.headUrl"></wd-img>
  107. <div class="text-black/90 text-sm font-normal font-['PingFang_SC'] leading-[10.18px]">
  108. {{ data.stylistName }}
  109. </div>
  110. </div>
  111. </template>
  112. </NavBarEvo>
  113. <!-- <div class="my-4 text-black/90 text-lg font-normal font-['PingFang_SC'] leading-[10.18px]">
  114. {{ data?.detailsDesc }}
  115. </div> -->
  116. <template v-if="swiperSizes && !isVideo">
  117. <div>
  118. <swiper class="" :style="swiperStyle" @change="handleChange">
  119. <template v-for="it of data?.bannerUrls" :key="it">
  120. <swiper-item>
  121. <wd-img width="100%" :src="it" mode="widthFix"></wd-img>
  122. </swiper-item>
  123. </template>
  124. </swiper>
  125. </div>
  126. </template>
  127. <template v-if="isVideo">
  128. <video width="100%" class="w-full aspect-[1.64/1]" :src="data?.bannerUrls[0]"></video>
  129. </template>
  130. <!-- <wd-swiper
  131. v-model="current"
  132. custom-class="my-1"
  133. autoplay="false"
  134. :list="data?.images"
  135. :indicator="{ type: 'fraction' }"
  136. indicatorPosition="top-right"
  137. imageMode="widthFix"
  138. ></wd-swiper> -->
  139. <view class="m-3.5">
  140. <div class="text-black/90 text-base font-normal font-['PingFang_SC'] leading-[10.18px]">
  141. {{ data?.circleDesc }}
  142. </div>
  143. <view class="my-5.5 flex gap-3.5 flex-wrap">
  144. <!-- <TiltedButton>按钮</TiltedButton> -->
  145. <template v-if="data?.tagName !== ''">
  146. <template v-for="it of data?.tagName?.split(',')" :key="it">
  147. <Tag>{{ it }}</Tag>
  148. </template>
  149. </template>
  150. </view>
  151. <div class="text-black/30 text-xs font-normal font-['PingFang_SC'] leading-[10.18px]">
  152. {{ dayjs(data.createTime).format('YYYY-MM-DD HH:mm') }}
  153. </div>
  154. <!-- <view class="flex items-center my-4">
  155. <view class="flex items-center">
  156. <avatar-group-casual
  157. :show-number="3"
  158. :urls="[
  159. 'https://via.placeholder.com/20x20',
  160. 'https://via.placeholder.com/20x20',
  161. 'https://via.placeholder.com/20x20',
  162. ]"
  163. ></avatar-group-casual>
  164. <div
  165. class="ml-1 text-black/60 text-sm font-normal font-['PingFang_SC'] leading-[10.18px]"
  166. >
  167. {{ circleUpvotes.total }}人赞过
  168. </div>
  169. </view>
  170. <view class="flex-1"></view>
  171. <view><wd-icon class="text-black/65" name="arrow-right" size="22px"></wd-icon></view>
  172. </view> -->
  173. <div class="h-0.25 bg-[#dadada] my-7"></div>
  174. <SectionHeading :title="`评论`" size="base">
  175. <template #append>
  176. <view v-if="reviews?.list" class="flex">
  177. <div class="text-black/90 text-xs font-normal font-['PingFang_SC'] leading-[10.18px]">
  178. 按热度
  179. </div>
  180. <div
  181. class="mx-2 text-black/40 text-xs font-normal font-['PingFang_SC'] leading-[10.18px]"
  182. >
  183. |
  184. </div>
  185. <div class="text-black/40 text-xs font-normal font-['PingFang_SC'] leading-[10.18px]">
  186. 按时间
  187. </div>
  188. </view>
  189. </template>
  190. </SectionHeading>
  191. <view clas="mt-8.25">
  192. <template v-if="reviews?.list.length">
  193. <template v-for="it of reviews?.list" :key="it.id">
  194. <CommentItem
  195. :options="it"
  196. :isChild="false"
  197. @upvote="runGetReviews()"
  198. @delete="runGetReviews()"
  199. ></CommentItem>
  200. <!-- <template v-for="child of it.childrens" :key="child.id">
  201. <CommentItem :options="child" :isChild="true"></CommentItem>
  202. </template> -->
  203. </template>
  204. </template>
  205. <template v-else>
  206. <view class="flex items-center justify-center mt-26 mb-36">
  207. <div class="text-black/40 text-xs font-normal font-['PingFang_SC'] leading-[10.18px]">
  208. 这里空空的
  209. </div>
  210. <div
  211. class="ml-1.5 text-[#2f4471]/90 text-xs font-normal font-['PingFang_SC'] leading-[10.18px]"
  212. >
  213. 点击评论~
  214. </div>
  215. </view>
  216. </template>
  217. </view>
  218. </view>
  219. <BottomAppBar fixed placeholder border custom-class="">
  220. <div class="bg-white flex items-center">
  221. <div class="w-[168px] bg-[#f6f6f6] rounded-[60px] px-3.5 py-2 flex items-center">
  222. <wd-input
  223. custom-class="bg-transparent!"
  224. no-border
  225. confirm-type="send"
  226. v-model="reviewContent"
  227. placeholder="说点什么..."
  228. @confirm="handleSend"
  229. ></wd-input>
  230. </div>
  231. <view class="flex justify-around flex-1">
  232. <div>
  233. <button open-type="share" class="bg-transparent! p-0!">
  234. <view
  235. class="flex flex-col items-center text-[rgba(0,0,0,0.85)] text-3.5 font-400 line-height-5.5"
  236. >
  237. <div class="w-4.5 h-4.5 flex items-center justify-center">
  238. <wd-img width="15" height="15" src="/static/svgs/share.svg"></wd-img>
  239. </div>
  240. <view class="">{{ data?.shareCount || 0 }}</view>
  241. </view>
  242. </button>
  243. </div>
  244. <view
  245. class="flex flex-col items-center text-[rgba(0,0,0,0.85)] text-3.5 font-400 line-height-5.5"
  246. >
  247. <div class="w-4.5 h-4.5 flex items-center justify-center">
  248. <wd-img width="15" height="15" src="/static/svgs/comment.svg"></wd-img>
  249. </div>
  250. <view class="">{{ data?.reviewCount }}</view>
  251. </view>
  252. <view
  253. class="flex flex-col items-center text-[rgba(0,0,0,0.85)] text-3.5 font-400 line-height-5.5"
  254. @click="
  255. handleUpvoteClick(
  256. {
  257. upvote: data.ownUpvote,
  258. circleId: data.id,
  259. userId: userInfo.userId,
  260. userName: userInfo.nickname,
  261. },
  262. () => run(),
  263. )
  264. "
  265. >
  266. <template v-if="data.ownUpvote">
  267. <wd-img width="18" height="18" :src="likeActived"></wd-img>
  268. </template>
  269. <template v-else>
  270. <wd-img width="18" height="18" :src="likeBlack"></wd-img>
  271. </template>
  272. <view>{{ data.upvoteCount }}</view>
  273. </view>
  274. </view>
  275. </div>
  276. </BottomAppBar>
  277. </view>
  278. </template>