search.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. <template>
  2. <view class="search-page">
  3. <!-- 顶部导航栏 -->
  4. <view class="nav-header" :style="{ paddingTop: (12 + statusBarHeight) + 'px' }">
  5. <view class="nav-left" @click="goBack">
  6. <u-icon name="arrow-leftward" color="rgba(51, 51, 51, 1)" size="42"></u-icon>
  7. </view>
  8. <view class="nav-center">
  9. <text class="nav-title">消息搜索</text>
  10. </view>
  11. <view class="nav-right"></view>
  12. </view>
  13. <!-- 搜索框 -->
  14. <view class="search-container">
  15. <view class="search-box">
  16. <u-icon name="search" color="rgba(153, 153, 153, 1)" size="32" style="margin-right: 20rpx;"></u-icon>
  17. <input
  18. v-model="searchKeyword"
  19. class="search-input"
  20. placeholder="请输入搜索内容"
  21. placeholder-style="color: #999; font-size: 14px;"
  22. @confirm="onSearchConfirm"
  23. />
  24. </view>
  25. <view class="cancel-btn" @click="onSearchConfirm">
  26. <text class="confirm-text">搜索</text>
  27. </view>
  28. </view>
  29. <!-- 加载状态 -->
  30. <view class="loading-state" v-if="loading && !searchKeyword">
  31. <text class="loading-text">加载中...</text>
  32. </view>
  33. <!-- 搜索结果 -->
  34. <view class="search-results" v-if="searchResults.length > 0">
  35. <view class="margin-top-sm content">
  36. <view class="radius padding-lr-sm bg" style="margin-top: 4rpx;" @click="goToChat(item)"
  37. v-for="(item,index) in searchResults" :key='index'>
  38. <view class="flex padding-tb">
  39. <view class="avatar-container">
  40. <u-image shape="circle" width='80rpx' height="80rpx" :src="item.avatar"></u-image>
  41. <view class="online-dot" v-if="item.onlineStatus == 'ONLINE'"></view>
  42. </view>
  43. <view class="flex-sub margin-left-sm">
  44. <view class="flex justify-between align-center">
  45. <view class="text-white flex align-center userNameleng">
  46. <view class="text-white" style="font-size: 28rpx;">
  47. {{item.userName}}
  48. </view>
  49. <text class="text-grey" style="font-size: 22rpx;margin-left: 10rpx;">
  50. <template v-if="userType == 2">
  51. {{ item.companyName }}
  52. <text> | </text>
  53. {{ item.hrPosition }}
  54. </template>
  55. <template v-else>{{ item.stationName }}</template>
  56. </text>
  57. </view>
  58. <view class="text-grey">{{item.createTime ? getMonthOrDay(item.createTime) : ''}}</view>
  59. </view>
  60. <view class="flex justify-between" style="margin-top: 10rpx;">
  61. <view class="text-grey" v-if="item.messageType == 1">{{item.content}}</view>
  62. <view class="text-grey" v-else-if="item.messageType == 2">[图片]</view>
  63. <view class="text-grey" v-else-if="item.messageType == 3">[语音]</view>
  64. <view class="text-grey" v-else-if="item.messageType == 4">[表情]</view>
  65. <view class="text-grey" v-else-if="item.messageType == 5">手机号请求</view>
  66. <view class="text-grey" v-else-if="item.messageType == 6">微信请求</view>
  67. <view class="text-grey" v-else-if="item.messageType == 7">[交换手机]</view>
  68. <view class="text-grey" v-else-if="item.messageType == 8">[交换微信]</view>
  69. <view class="text-grey" v-else-if="item.messageType == 9">简历请求</view>
  70. <view class="text-grey" v-else-if="item.messageType == 10">简历已发送</view>
  71. <view class="text-grey" v-else-if="item.messageType == 12">{{item.content}}已拒绝</view>
  72. <view class="text-grey" v-else-if="item.messageType == 18">位置</view>
  73. <view class="text-grey" v-else-if="item.messageType == 20">[视频通话]</view>
  74. <view class="text-grey" v-else-if="item.messageType == 21">[语音通话]</view>
  75. <view class="text-grey" v-else-if="item.messageType == 96 || item.messageType == 97 || item.messageType == 98">[{{item.content}}]</view>
  76. <view class="text-grey" v-else-if="item.messageType == 99">[面试邀约]</view>
  77. <view v-else>[其他消息类型]</view>
  78. </view>
  79. </view>
  80. </view>
  81. </view>
  82. </view>
  83. </view>
  84. <!-- 无搜索结果 -->
  85. <view class="no-results" v-if="searchKeyword && searchResults.length === 0 && !loading">
  86. <text class="no-results-text">暂无搜索结果</text>
  87. </view>
  88. <!-- 默认状态 -->
  89. <view class="default-state" v-if="!searchKeyword && !loading && !searchResults.length">
  90. <text class="default-text">请输入关键词搜索消息</text>
  91. </view>
  92. </view>
  93. </template>
  94. <script>
  95. export default {
  96. data() {
  97. return {
  98. statusBarHeight: 0, // 状态栏高度
  99. searchKeyword: '',
  100. searchResults: [],
  101. allChatList: [], // 存储所有聊天记录
  102. page: 1,
  103. limit: 10,
  104. total: 0,
  105. loading: false,
  106. hasMore: true,
  107. userType: null
  108. }
  109. },
  110. onLoad() {
  111. // 获取状态栏高度
  112. let systemInfo = uni.getSystemInfoSync();
  113. this.statusBarHeight = systemInfo.statusBarHeight || 0;
  114. // 页面加载时获取聊天记录
  115. // this.getChatList()
  116. this.userType = this.$queue.getData('userType') || null
  117. },
  118. // 下拉刷新
  119. onPullDownRefresh() {
  120. this.page = 1
  121. this.hasMore = true
  122. // this.getChatList()
  123. setTimeout(() => {
  124. uni.stopPullDownRefresh()
  125. }, 1000)
  126. },
  127. methods: {
  128. goBack() {
  129. uni.navigateBack()
  130. },
  131. // onSearchInput(e) {
  132. // this.searchKeyword = e.detail.value
  133. // this.performSearch()
  134. // },
  135. onSearchConfirm() {
  136. // this.performSearch()
  137. if (!this.searchKeyword.trim()) {
  138. return this.$queue.showToast('请输入搜索内容')
  139. }
  140. this.getChatRecord()
  141. },
  142. // 获取聊天记录列表
  143. getChatList() {
  144. if (this.loading) return
  145. this.loading = true
  146. this.$Request.get("/app/chat/selectChatConversationPage", {
  147. page: this.page,
  148. limit: this.limit
  149. }).then(res => {
  150. this.loading = false
  151. if (res.code == 0) {
  152. if (this.page === 1) {
  153. this.allChatList = res.data.list || []
  154. } else {
  155. this.allChatList = this.allChatList.concat(res.data.list || [])
  156. }
  157. // 检查是否还有更多数据
  158. if (res.data.list && res.data.list.length < this.limit) {
  159. this.hasMore = false
  160. }
  161. // 如果有搜索关键词,执行搜索
  162. if (this.searchKeyword.trim()) {
  163. this.performSearch()
  164. }
  165. }
  166. }).catch(err => {
  167. this.loading = false
  168. console.error('获取聊天记录失败:', err)
  169. })
  170. },
  171. // 执行搜索
  172. performSearch() {
  173. if (!this.searchKeyword.trim()) {
  174. this.searchResults = []
  175. return
  176. }
  177. console.log('搜索关键词:', this.searchKeyword)
  178. // 从所有聊天记录中搜索,直接使用原始数据结构
  179. this.searchResults = this.allChatList.filter(item => {
  180. const keyword = this.searchKeyword.toLowerCase()
  181. return (
  182. (item.userName && item.userName.toLowerCase().includes(keyword)) ||
  183. (item.content && item.content.toLowerCase().includes(keyword)) ||
  184. (item.stationName && item.stationName.toLowerCase().includes(keyword))
  185. )
  186. })
  187. },
  188. // 把时间转换为月日(与首页保持一致)
  189. getMonthOrDay(time) {
  190. let date = new Date(time) // 获取时间
  191. let month = date.getMonth() + 1 // 获取月
  192. let strDate = date.getDate() // 获取日
  193. return month + '月' + strDate + '日'
  194. },
  195. goToChat(item) {
  196. // 跳转到聊天页面,使用与首页相同的跳转方式
  197. uni.navigateTo({
  198. url: `/pages/msg/im?chatConversationId=${item.chatConversationId}&byUserId=${item.focusedUserId}&postPushId=${item.postPushId}&resumesId=${item.resumesId}`
  199. })
  200. },
  201. getChatRecord() {
  202. if (this.loading) return
  203. this.loading = true
  204. uni.showLoading({ title: '加载中' })
  205. this.$Request.getT('/app/chat/searchConversation', {
  206. page: this.page,
  207. limit: this.limit,
  208. key: this.searchKeyword.toLowerCase()
  209. }).then(res => {
  210. console.log(res)
  211. if (res.code == 0) {
  212. this.searchResults = this.page == 1 ? res.data.records : [...this.searchResults, ...res.data.records]
  213. }
  214. }).finally(() => {
  215. this.loading = false
  216. uni.hideLoading()
  217. })
  218. }
  219. }
  220. }
  221. </script>
  222. <style lang="scss" scoped>
  223. .search-page {
  224. min-height: 100vh;
  225. // padding: 80rpx 0 0 0;
  226. }
  227. .nav-header {
  228. display: flex;
  229. align-items: center;
  230. justify-content: space-between;
  231. padding-left: 30rpx;
  232. padding-right: 30rpx;
  233. padding-bottom: 20rpx;
  234. background-color: #ffffff;
  235. .nav-left, .nav-right {
  236. width: 60rpx;
  237. height: 60rpx;
  238. display: flex;
  239. align-items: center;
  240. justify-content: center;
  241. }
  242. .nav-center {
  243. flex: 1;
  244. text-align: center;
  245. }
  246. .nav-title {
  247. color: rgba(51, 51, 51, 1);
  248. font-family: DM Sans;
  249. font-size: 20px;
  250. font-weight: 600;
  251. line-height: 26px;
  252. letter-spacing: undefined;
  253. text-align: center;
  254. }
  255. }
  256. .search-container {
  257. display: flex;
  258. align-items: center;
  259. padding: 20rpx 30rpx;
  260. background-color: #ffffff;
  261. border-bottom: 1rpx solid #f0f0f0;
  262. .search-box {
  263. flex: 1;
  264. display: flex;
  265. align-items: center;
  266. background-color:rgba(241, 241, 241, 1);
  267. border-radius: 38rpx;
  268. padding: 15rpx 30rpx;
  269. margin-right: 20rpx;
  270. .search-input {
  271. color: rgba(153, 153, 153, 1);
  272. font-family: DM Sans;
  273. font-size: 12px;
  274. font-weight: 500;
  275. line-height: 24px;
  276. letter-spacing: undefined;
  277. text-align: left;
  278. }
  279. }
  280. .cancel-btn {
  281. padding: 10rpx 20rpx;
  282. .confirm-text {
  283. color: rgba(1, 107, 246, 1);
  284. font-family: DM Sans;
  285. font-size: 14px;
  286. font-weight: 500;
  287. line-height: 24px;
  288. letter-spacing: undefined;
  289. text-align: center;
  290. }
  291. }
  292. }
  293. .search-results {
  294. padding: 20rpx 0;
  295. .result-item {
  296. display: flex;
  297. align-items: flex-start;
  298. padding: 30rpx;
  299. background-color: #ffffff;
  300. margin-bottom: 2rpx;
  301. &:active {
  302. background-color: #f5f5f5;
  303. }
  304. .avatar-container {
  305. position: relative;
  306. width: 80rpx;
  307. height: 80rpx;
  308. margin-right: 30rpx;
  309. .avatar {
  310. width: 80rpx;
  311. height: 80rpx;
  312. border-radius: 50%;
  313. }
  314. .online-dot {
  315. position: absolute;
  316. bottom: 0rpx;
  317. right: 5rpx;
  318. width: 20rpx;
  319. height: 20rpx;
  320. background-color: #00ff00;
  321. border-radius: 50%;
  322. border: 2rpx solid #ffffff;
  323. }
  324. }
  325. .result-content {
  326. flex: 1;
  327. .result-header {
  328. display: flex;
  329. justify-content: space-between;
  330. align-items: center;
  331. margin-bottom: 10rpx;
  332. .user-name {
  333. font-size: 32rpx;
  334. font-weight: 500;
  335. color: rgba(29, 33, 41, 1);
  336. }
  337. .message-date {
  338. font-size: 24rpx;
  339. color: rgba(153, 153, 153, 1);
  340. }
  341. }
  342. .result-info {
  343. margin-bottom: 10rpx;
  344. .company-info {
  345. font-size: 28rpx;
  346. color: rgba(102, 102, 102, 1);
  347. }
  348. }
  349. .message-preview {
  350. .preview-text {
  351. font-size: 28rpx;
  352. color: rgba(153, 153, 153, 1);
  353. line-height: 1.4;
  354. }
  355. }
  356. }
  357. }
  358. }
  359. // 引入首页的样式
  360. .margin-top-sm {
  361. margin-top: 0 !important;
  362. }
  363. .content {
  364. padding: 0 20rpx;
  365. }
  366. .radius {
  367. border-radius: 15rpx;
  368. }
  369. .padding-lr-sm {
  370. padding-left: 20rpx;
  371. padding-right: 20rpx;
  372. }
  373. .bg {
  374. background-color: #ffffff;
  375. }
  376. .flex {
  377. display: flex;
  378. }
  379. .padding-tb {
  380. padding-top: 20rpx;
  381. padding-bottom: 20rpx;
  382. }
  383. .flex-sub {
  384. flex: 1;
  385. }
  386. .margin-left-sm {
  387. margin-left: 20rpx;
  388. }
  389. .justify-between {
  390. justify-content: space-between;
  391. }
  392. .align-center {
  393. align-items: center;
  394. }
  395. .text-white {
  396. color: #333333;
  397. }
  398. .text-grey {
  399. color: #999999;
  400. }
  401. .userNameleng {
  402. max-width: 400rpx;
  403. overflow: hidden;
  404. text-overflow: ellipsis;
  405. white-space: nowrap;
  406. }
  407. .avatar-container {
  408. position: relative;
  409. width: 80rpx;
  410. height: 80rpx;
  411. }
  412. .online-dot {
  413. position: absolute;
  414. bottom: 0rpx;
  415. right: 5rpx;
  416. width: 20rpx;
  417. height: 20rpx;
  418. background-color: #00ff00;
  419. border-radius: 50%;
  420. border: 2rpx solid #ffffff;
  421. }
  422. .loading-state, .no-results, .default-state {
  423. display: flex;
  424. justify-content: center;
  425. align-items: center;
  426. padding: 100rpx 0;
  427. .loading-text, .no-results-text, .default-text {
  428. font-size: 28rpx;
  429. color: rgba(153, 153, 153, 1);
  430. }
  431. }
  432. </style>