single-add.vue 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. <template>
  2. <div class="w-full h-[100vh]">
  3. <ChatHeaderBar title="选择互关好友" />
  4. <ChatSearch v-model:searchString="showName" @search="search" placeholder="请输入关键词" />
  5. <van-pull-refresh v-model="refreshing" @refresh="onRefresh">
  6. <ChatEmpty
  7. image="search"
  8. v-if="!addDataList?.length && !loading"
  9. title="暂无数据"
  10. top="100"
  11. />
  12. <van-list
  13. v-else-if="addDataList.length"
  14. v-model:loading="loading"
  15. error-text="获取失败"
  16. finished-text="-- 没有更多了 --"
  17. :finished="finished"
  18. :immediate-check="false"
  19. >
  20. <!-- @load="getLoadList" -->
  21. <div style="height: calc(100vh - 170px)">
  22. <van-checkbox-group v-model="checked">
  23. <!-- <van-index-bar highlight-color="#FD9A00" index-list :sticky="false"> -->
  24. <template v-for="(item, index) in addDataList" :key="item?.attentionIdDictMap?.userId">
  25. <!-- <van-index-anchor index="A" /> -->
  26. <van-cell center clickable @click="toggle(item)">
  27. <template #icon>
  28. <div class="flex justify-start">
  29. <van-checkbox
  30. checked-color="#FD9A00"
  31. :name="item?.attentionIdDictMap?.userId"
  32. :ref="(el) => (checkboxRefs[item?.attentionIdDictMap?.userId] = el)"
  33. @click.stop="toggle(item)"
  34. />
  35. <div class="w-40 h-40 ml-13 mr-12 rounded-full overflow-hidden">
  36. <img
  37. v-if="item?.attentionIdDictMap?.headImageUrl"
  38. class="w-full h-full shrink-0 object-cover"
  39. :src="item?.attentionIdDictMap?.headImageUrl"
  40. alt=""
  41. />
  42. <img
  43. class="w-full h-full shrink-0 object-cover"
  44. src="~/assets/img/default_avatar.png"
  45. alt=""
  46. />
  47. </div>
  48. </div>
  49. </template>
  50. <template #title>
  51. <div class="flex items-center">
  52. <h1 class="text-xl text-black-3">
  53. {{ item?.attentionIdDictMap?.showName }}
  54. </h1>
  55. <van-tag
  56. v-if="item.fansStatus == 2"
  57. style="margin-left: 5px; padding: 3px 6px"
  58. color="#F7F8FA"
  59. text-color="#666666"
  60. >
  61. 相互关注
  62. </van-tag>
  63. </div>
  64. </template>
  65. </van-cell>
  66. </template>
  67. <!-- </van-index-bar> -->
  68. </van-checkbox-group>
  69. </div>
  70. </van-list>
  71. </van-pull-refresh>
  72. <div
  73. class="w-full box-border p-16 pb-40 bg-white fixed bottom-0 left-0 flex justify-between items-center shadow-[0px_-4px_4px_0px_rgba(0,0,0,0.1)]"
  74. >
  75. <div class="shrink-0 flex justify-start items-center">
  76. <div class="w-118 shrink-0 flex justify-start items-center overflow-hidden">
  77. <div
  78. v-for="(item, index) in checkedList.slice(0, 5)"
  79. :key="index + 'avatar'"
  80. :class="`w-36 h-36 ${index == 0 ? '' : '-ml-16'} shrink-0 rounded-full overflow-hidden`"
  81. >
  82. <img
  83. v-if="item?.attentionIdDictMap?.headImageUrl"
  84. class="w-full h-full object-cover"
  85. :src="item?.attentionIdDictMap?.headImageUrl"
  86. alt=""
  87. />
  88. <img
  89. v-else
  90. class="w-full h-full shrink-0 object-cover"
  91. src="~/assets/img/default_avatar.png"
  92. alt=""
  93. />
  94. </div>
  95. </div>
  96. <div v-if="checkedList.length > 5" class="shrink-0 w-24 h-24 ml-8">
  97. <img class="w-full h-full object-cover" src="~/assets/img/chat/ellipsis.svg" alt="" />
  98. </div>
  99. </div>
  100. <van-button
  101. :loading="isLoading"
  102. :disabled="checkedList.length > 0 ? false : true"
  103. @click="handleCreateGroup"
  104. style="width: 160px"
  105. class="shrink-0"
  106. block
  107. size="large"
  108. color="#FD9A00"
  109. round
  110. >
  111. 新建
  112. <span v-if="checkedList.length">({{ checkedList.length }})</span>
  113. </van-button>
  114. </div>
  115. </div>
  116. </template>
  117. <script setup>
  118. const route = useRoute()
  119. const router = useRouter()
  120. definePageMeta({
  121. layout: false
  122. })
  123. onMounted(() => {
  124. getList()
  125. })
  126. // 对方的那个id
  127. const toUserId = computed(() => route.query?.toUserId ?? '')
  128. const refreshing = ref(false)
  129. const loading = ref(false)
  130. const finished = ref(false)
  131. const checked = ref([])
  132. const checkedList = ref([])
  133. const showName = ref('')
  134. const checkboxRefs = ref([])
  135. // 字母的数组
  136. const letterList = ref([])
  137. const queryParams = reactive({
  138. pageNum: 1,
  139. pageSize: 10,
  140. flagPage: 1
  141. })
  142. const addDataList = ref([])
  143. const filterDataList = ref([])
  144. const searchText = computed(() => (showName.value ? '暂无互关好友' : '暂无搜索结果'))
  145. // 选中要邀请的人
  146. const toggle = (item) => {
  147. let index = checkedList.value.findIndex(
  148. (el) => el?.attentionIdDictMap?.userId == item?.attentionIdDictMap?.userId
  149. )
  150. if (index != -1) {
  151. checkedList.value.splice(index, 1)
  152. } else {
  153. checkedList.value.push(item)
  154. }
  155. checkboxRefs.value[item?.attentionIdDictMap?.userId].toggle()
  156. }
  157. const search = () => {
  158. finished.value = true
  159. if (showName.value) {
  160. addDataList.value = filterDataList.value.filter((item) =>
  161. item.attentionIdDictMap.name.includes(showName.value)
  162. )
  163. } else {
  164. addDataList.value = filterDataList.value
  165. }
  166. }
  167. // 刷新
  168. const onRefresh = () => {
  169. queryParams.pageNum = 1
  170. addDataList.value = []
  171. filterDataList.value = []
  172. getList()
  173. }
  174. // 获取数据
  175. const getList = async () => {
  176. try {
  177. let url = `/website/tourism/fans/getFriends`
  178. loading.value = true
  179. let {
  180. data: { dataList, totalCount }
  181. } = await request(url, {
  182. query: {
  183. ...queryParams
  184. }
  185. })
  186. if (Array.isArray(dataList) && dataList?.length) {
  187. addDataList.value = dataList
  188. nextTick(() => {
  189. checkboxRefs.value[toUserId.value].toggle()
  190. let item = dataList.find((el) => el?.attentionIdDictMap?.userId == toUserId.value)
  191. if (item) {
  192. checkedList.value.push(item)
  193. } else {
  194. router.back()
  195. }
  196. })
  197. } else {
  198. addDataList.value = []
  199. }
  200. loading.value = false
  201. refreshing.value = false
  202. if (addDataList.value.length >= totalCount) {
  203. finished.value = true
  204. } else {
  205. finished.value = false
  206. }
  207. } catch (err) {
  208. } finally {
  209. refreshing.value = false
  210. loading.value = false
  211. }
  212. }
  213. // 节流
  214. const isLoading = ref(false)
  215. function handleKeyDown(event) {
  216. // 启动节流
  217. // 1000ms 后解除节流
  218. // setTimeout(() => {
  219. // isThrottled.value = false
  220. // }, 3000)
  221. }
  222. // 创建多人聊天
  223. async function handleCreateGroup() {
  224. if (!isLoading.value) {
  225. isLoading.value = true
  226. try {
  227. showLoadingToast({
  228. message: '准备开始群聊...',
  229. duration: 100000
  230. })
  231. let { data } = await request('/website/tourGroup/createGroup', {
  232. method: 'post',
  233. body: {
  234. createType: 2,
  235. ids: [...checked.value]
  236. }
  237. })
  238. if (data) {
  239. navigateTo({
  240. path: '/chat/group-chat',
  241. query: {
  242. groupId: data
  243. },
  244. replace: true
  245. })
  246. isLoading.value = false
  247. }
  248. } catch (error) {
  249. } finally {
  250. closeToast()
  251. }
  252. }
  253. }
  254. useSeoMeta({
  255. title: '我的消息'
  256. })
  257. </script>
  258. <style lang="scss" scoped></style>