invite-list.vue 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. <template>
  2. <div class="content" v-show-log="state.log_invite_list_show">
  3. <div class="error" v-if="state.invited_list.length == 0">
  4. Invite people to hunt treasure with you!
  5. </div>
  6. <div class="list" v-else @scroll="handleScroll($event)">
  7. <div class="item" v-for="item in state.invited_list">
  8. <div class="left">
  9. <img :src="item.userInfo.avatarUrl" alt="" @click="clickItem(item)" />
  10. </div>
  11. <div class="right">
  12. <div>{{ item.userInfo.nickName }}</div>
  13. <div>{{ getTime(item.timestamp) }}</div>
  14. </div>
  15. </div>
  16. </div>
  17. <div class="footer">
  18. <v-btn :txt="state.open_btn.txt" :font-size="'17px'" class="btn" :icon="false" :loading="state.btn_loading"
  19. :disabled="state.open_btn.disabled" v-click-log="state.log_invite_btn_click" @onClick="clickBtn"
  20. font-weight="600"></v-btn>
  21. </div>
  22. </div>
  23. </template>
  24. <script setup>
  25. import VBtn from '@/view/iframe/treasure-hunt/components/btn.vue'
  26. import { inviteList, inviteListRefresh } from '@/http/treasure'
  27. import { inject, onMounted } from 'vue'
  28. import Report from "@/log-center/log"
  29. var moment = require('moment')
  30. let state = inject('state')
  31. state.invited_list = []
  32. let page_num = 1
  33. let page_size = 10
  34. let list_end = false
  35. state.log_invite_btn_click = {
  36. businessType: Report.businessType.buttonClick,
  37. pageSource: Report.pageSource.inviteFriendsPage,
  38. objectType: Report.objectType.openChestButton,
  39. redPacketType: Report.redPacketType.treasure,
  40. shareLinkId: state.invite_code,
  41. myShareLinkId: state.detail.inviteCopyUrl,
  42. currentInvitedNum: state.inviteCount,
  43. postId: state.postId
  44. }
  45. state.log_invite_list_show = {
  46. businessType: Report.businessType.pageView,
  47. pageSource: Report.pageSource.beenInvitedPage,
  48. redPacketType: Report.redPacketType.treasure,
  49. shareLinkId: state.invite_code,
  50. myShareLinkId: state.detail.inviteCopyUrl,
  51. currentInvitedNum: state.inviteCount,
  52. postId: state.postId
  53. }
  54. onMounted(() => {
  55. state.btn_loading = false
  56. list()
  57. })
  58. const clickItem = (item) => {
  59. window.open(`https://twitter.com/${item.userInfo.nickName}`)
  60. }
  61. function handleScroll(e) {
  62. if (list_end) {
  63. return
  64. }
  65. e = e.target
  66. if ((e.clientHeight + e.scrollTop) / e.scrollHeight > .8) {
  67. list_end = true
  68. inviteListScroll()
  69. }
  70. }
  71. const list = () => {
  72. inviteListScroll()
  73. }
  74. // 刷新时调用
  75. state.inviteListRefresh = () => {
  76. let last_timestamp = 0
  77. if (state.invited_list.length > 0) {
  78. last_timestamp = state.invited_list[0].last_timestamp
  79. }
  80. inviteListRefresh({
  81. params: {
  82. postId: state.postId,
  83. lastTimestamp: last_timestamp,
  84. }
  85. }).then((res) => {
  86. if (res.code == 0) {
  87. handleCommon(res.data)
  88. }
  89. })
  90. }
  91. const handleCommon = (data) => {
  92. state.inviteCount = data.inviteCount
  93. if (state.inviteCount > 0) {
  94. state.tabs[1].txt = `invited(${state.inviteCount})`
  95. }
  96. if (data.inviteUsers.length > 0) {
  97. data.inviteUsers.forEach(item => {
  98. if (state.invited_list.filter((item2) => { return item2.userInfo.uid == item.userInfo.uid }).length == 0) {
  99. state.invited_list.push(item)
  100. }
  101. })
  102. state.invited_list.sort((a, b) => {
  103. return a.lastTimestamp - b.lastTimestamp
  104. })
  105. list_end = false
  106. } else {
  107. list_end = false
  108. }
  109. }
  110. // 滚动和初始化
  111. let inviteListScroll = () => {
  112. // state.invited_list
  113. let last_timestamp = 0
  114. let len = state.invited_list.length
  115. if (len > 0) {
  116. last_timestamp = state.invited_list[len - 1].lastTimestamp
  117. }
  118. inviteList({
  119. params: {
  120. inviteCode: state.invite_code,
  121. postId: state.postId,
  122. lastTimestamp: last_timestamp,
  123. pageSize: page_size
  124. }
  125. }).then((res) => {
  126. if (res.code == 0) {
  127. handleCommon(res.data)
  128. }
  129. })
  130. }
  131. const getTime = (timestamp) => {
  132. let _d1 = moment(new Date().getTime())
  133. let _d2 = moment(timestamp)
  134. const plural = (n, s) => {
  135. let _str = `${n} ${s} ago`
  136. if (n > 1) {
  137. _str = `${n} ${s}s ago`
  138. }
  139. return _str
  140. }
  141. let _d = moment.duration(_d1.diff(_d2)).days()
  142. if (_d) {
  143. return plural(_d, 'day')
  144. }
  145. let _h = moment.duration(_d1.diff(_d2)).hours()
  146. if (_h) {
  147. return plural(_h, 'hour')
  148. }
  149. let _m = moment.duration(_d1.diff(_d2)).minutes()
  150. if (_m) {
  151. return plural(_m, 'min')
  152. }
  153. let _s = moment.duration(_d1.diff(_d2)).seconds()
  154. return plural(_s, 'sec')
  155. }
  156. async function clickBtn() {
  157. let _userInfo = await state.checkIsLogin()
  158. if (!_userInfo) {
  159. return
  160. }
  161. state.btn_loading = true
  162. state.treasureOpen()
  163. }
  164. </script>
  165. <style lang="scss" scoped>
  166. .content {
  167. position: relative;
  168. height: 292px;
  169. .footer {
  170. background: #fff;
  171. padding: 10px 16px 25px 16px;
  172. }
  173. .error {
  174. height: 204px;
  175. color: #BABABA;
  176. background-color: #fff;
  177. font-weight: 500;
  178. font-size: 15px;
  179. line-height: 204px;
  180. text-align: center;
  181. }
  182. .list {
  183. background: #fff;
  184. height: 204px;
  185. overflow-y: auto;
  186. .item {
  187. height: 60px;
  188. display: flex;
  189. align-items: center;
  190. .left {
  191. width: 58px;
  192. text-align: center;
  193. img {
  194. border-radius: 50px;
  195. width: 30px;
  196. height: 30px;
  197. }
  198. }
  199. .right {
  200. flex: 1;
  201. border-bottom: 1px solid #D9D9D9;
  202. display: flex;
  203. align-items: center;
  204. height: 100%;
  205. justify-content: space-between;
  206. div:nth-child(1) {
  207. color: #000000;
  208. font-weight: 500;
  209. font-size: 15px;
  210. }
  211. div:nth-child(2) {
  212. color: #A6A6A6;
  213. font-weight: 400;
  214. font-size: 12px;
  215. margin-right: 17px;
  216. }
  217. }
  218. }
  219. }
  220. }
  221. </style>